├── .gitignore ├── dnstap.pb ├── .gitignore ├── README.md ├── LICENSE └── dnstap.proto ├── go.mod ├── COPYRIGHT ├── genproto.sh ├── README ├── Encoder.go ├── dnstap ├── mirroroutput.go ├── fileoutput.go ├── dnstap.8 └── main.go ├── Decoder.go ├── Reader.go ├── Writer.go ├── dnstap.go ├── FrameStreamOutput.go ├── go.sum ├── TextOutput.go ├── FrameStreamInput.go ├── YamlFormat.go ├── FrameStreamSockInput.go ├── FrameStreamSockOutput.go ├── JsonFormat.go ├── QuietTextFormat.go ├── sock_test.go ├── SocketWriter.go ├── LICENSE └── dnstap.pb.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /dnstap.pb/.gitignore: -------------------------------------------------------------------------------- 1 | .deps/ 2 | .dirstamp 3 | .libs/ 4 | *.pb-c.c 5 | *.pb-c.h 6 | *.pb.cc 7 | *.pb.h 8 | *.pb.go 9 | *_pb2.py 10 | *_pb2.pyc 11 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dnstap/golang-dnstap 2 | 3 | require ( 4 | github.com/farsightsec/golang-framestream v0.3.0 5 | github.com/miekg/dns v1.1.31 6 | google.golang.org/protobuf v1.23.0 7 | ) 8 | -------------------------------------------------------------------------------- /dnstap.pb/README.md: -------------------------------------------------------------------------------- 1 | # dnstap: flexible, structured event replication format for DNS software 2 | 3 | This directory contains only the protobuf schemas for [dnstap](http://dnstap.info/), and is the root of 4 | a repository named "dnstap.pb". 5 | 6 | See the following repositories/links for implementations: 7 | - [golang-dnstap](https://github.com/dnstap/golang-dnstap): command-line tool and Golang package 8 | 9 | # Community 10 | 11 | There is a [mailing list](http://lists.redbarn.org/mailman/listinfo/dnstap) for everyone interested in discussing `dnstap`. 12 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 by Farsight Security, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /genproto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | go_package() { 4 | local file pkg line script 5 | file=$1; shift 6 | pkg=$1; shift 7 | 8 | line="option go_package = \"$pkg\";" 9 | grep "^$line\$" $file > /dev/null && return 10 | 11 | script="/^package dnstap/|a|$line|.|w|q|" 12 | if grep "^option go_package" $file > /dev/null; then 13 | script="/^option go_package/d|1|${script}" 14 | fi 15 | 16 | echo "$script" | tr '|' '\n' | ed $file || exit 17 | } 18 | 19 | dir=$(dirname $0) 20 | [ -n "$dir" ] && cd $dir 21 | 22 | cd dnstap.pb 23 | 24 | go_package dnstap.proto "github.com/dnstap/golang-dnstap;dnstap" 25 | protoc --go_out=../../../.. dnstap.proto 26 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | dnstap: flexible, structured event replication format for DNS servers 2 | --------------------------------------------------------------------- 3 | 4 | dnstap implements an encoding format for DNS server events. It uses a 5 | lightweight framing on top of event payloads encoded using Protocol Buffers and 6 | is transport neutral. 7 | 8 | dnstap can represent internal state inside a DNS server that is difficult to 9 | obtain using techniques based on traditional packet capture or unstructured 10 | textual format logging. 11 | 12 | This repository contains a command-line tool named "dnstap" developed in the 13 | Go programming language. It can be installed with the following command: 14 | 15 | go get -u github.com/dnstap/golang-dnstap/dnstap 16 | -------------------------------------------------------------------------------- /Encoder.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "google.golang.org/protobuf/proto" 21 | ) 22 | 23 | // An Encoder serializes and writes Dnstap messages to an underlying 24 | // dnstap Writer 25 | type Encoder struct { 26 | w Writer 27 | } 28 | 29 | // NewEncoder creates an Encoder using the given dnstap Writer 30 | func NewEncoder(w Writer) *Encoder { 31 | return &Encoder{w} 32 | } 33 | 34 | // Encode serializes and writes the Dnstap message m to the encoder's 35 | // Writer. 36 | func (e *Encoder) Encode(m *Dnstap) error { 37 | b, err := proto.Marshal(m) 38 | if err != nil { 39 | return err 40 | } 41 | 42 | _, err = e.w.WriteFrame(b) 43 | return err 44 | } 45 | -------------------------------------------------------------------------------- /dnstap/mirroroutput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | dnstap "github.com/dnstap/golang-dnstap" 21 | ) 22 | 23 | type mirrorOutput struct { 24 | outputs []dnstap.Output 25 | data chan []byte 26 | done chan struct{} 27 | } 28 | 29 | func newMirrorOutput() *mirrorOutput { 30 | return &mirrorOutput{ 31 | data: make(chan []byte, outputChannelSize), 32 | done: make(chan struct{}), 33 | } 34 | } 35 | 36 | func (mo *mirrorOutput) Add(o dnstap.Output) { 37 | mo.outputs = append(mo.outputs, o) 38 | } 39 | 40 | func (mo *mirrorOutput) RunOutputLoop() { 41 | for b := range mo.data { 42 | for _, o := range mo.outputs { 43 | o.GetOutputChannel() <- b 44 | } 45 | } 46 | for _, o := range mo.outputs { 47 | o.Close() 48 | } 49 | close(mo.done) 50 | } 51 | 52 | func (mo *mirrorOutput) Close() { 53 | close(mo.data) 54 | <-mo.done 55 | } 56 | 57 | func (mo *mirrorOutput) GetOutputChannel() chan []byte { 58 | return mo.data 59 | } 60 | -------------------------------------------------------------------------------- /Decoder.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | framestream "github.com/farsightsec/golang-framestream" 21 | "google.golang.org/protobuf/proto" 22 | ) 23 | 24 | // A Decoder reads and parses Dnstap messages from an io.Reader 25 | type Decoder struct { 26 | buf []byte 27 | r Reader 28 | } 29 | 30 | // NewDecoder creates a Decoder using the given dnstap Reader, accepting 31 | // dnstap data frames up to maxSize in size. 32 | func NewDecoder(r Reader, maxSize int) *Decoder { 33 | return &Decoder{ 34 | buf: make([]byte, maxSize), 35 | r: r, 36 | } 37 | } 38 | 39 | // Decode reads and parses a Dnstap message from the Decoder's Reader. 40 | // Decode silently discards data frames larger than the Decoder's configured 41 | // maxSize. 42 | func (d *Decoder) Decode(m *Dnstap) error { 43 | for { 44 | n, err := d.r.ReadFrame(d.buf) 45 | 46 | switch err { 47 | case framestream.ErrDataFrameTooLarge: 48 | continue 49 | case nil: 50 | break 51 | default: 52 | return err 53 | } 54 | 55 | return proto.Unmarshal(d.buf[:n], m) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Reader.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "io" 21 | "time" 22 | 23 | framestream "github.com/farsightsec/golang-framestream" 24 | ) 25 | 26 | // A Reader is a source of dnstap frames. 27 | type Reader interface { 28 | ReadFrame([]byte) (int, error) 29 | } 30 | 31 | // ReaderOptions specifies configuration for the Reader. 32 | type ReaderOptions struct { 33 | // If Bidirectional is true, the underlying io.Reader must also 34 | // satisfy io.Writer, and the dnstap Reader will use the bidirectional 35 | // Frame Streams protocol. 36 | Bidirectional bool 37 | // Timeout sets the timeout for reading the initial handshake and 38 | // writing response control messages to the underlying Reader. Timeout 39 | // is only effective if the underlying Reader is a net.Conn. 40 | Timeout time.Duration 41 | } 42 | 43 | // NewReader creates a Reader using the given io.Reader and options. 44 | func NewReader(r io.Reader, opt *ReaderOptions) (Reader, error) { 45 | if opt == nil { 46 | opt = &ReaderOptions{} 47 | } 48 | return framestream.NewReader(r, 49 | &framestream.ReaderOptions{ 50 | ContentTypes: [][]byte{FSContentType}, 51 | Timeout: opt.Timeout, 52 | Bidirectional: opt.Bidirectional, 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /Writer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "io" 21 | "time" 22 | 23 | framestream "github.com/farsightsec/golang-framestream" 24 | ) 25 | 26 | // A Writer writes dnstap frames to its destination. 27 | type Writer interface { 28 | WriteFrame([]byte) (int, error) 29 | Close() error 30 | } 31 | 32 | // WriterOptions specifies configuration for the Writer 33 | type WriterOptions struct { 34 | // If Bidirectional is true, the underlying io.Writer must also 35 | // satisfy io.Reader, and the dnstap Writer will use the bidirectional 36 | // Frame Streams protocol. 37 | Bidirectional bool 38 | // Timeout sets the write timeout for data and control messages and the 39 | // read timeout for handshake responses on the underlying Writer. Timeout 40 | // is only effective if the underlying Writer is a net.Conn. 41 | Timeout time.Duration 42 | } 43 | 44 | // NewWriter creates a Writer using the given io.Writer and options. 45 | func NewWriter(w io.Writer, opt *WriterOptions) (Writer, error) { 46 | if opt == nil { 47 | opt = &WriterOptions{} 48 | } 49 | return framestream.NewWriter(w, 50 | &framestream.WriterOptions{ 51 | ContentTypes: [][]byte{FSContentType}, 52 | Timeout: opt.Timeout, 53 | Bidirectional: opt.Bidirectional, 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /dnstap.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014,2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | //go:generate ./genproto.sh 18 | 19 | package dnstap 20 | 21 | const outputChannelSize = 32 22 | 23 | // FSContentType is the FrameStream content type for dnstap protobuf data. 24 | var FSContentType = []byte("protobuf:dnstap.Dnstap") 25 | 26 | // An Input is a source of dnstap data. It provides validation of the 27 | // content type and will present any data read or received on the channel 28 | // provided to the ReadInto method. 29 | type Input interface { 30 | ReadInto(chan []byte) 31 | Wait() 32 | } 33 | 34 | // An Output is a destination for dnstap data. It accepts data on the channel 35 | // returned from the GetOutputChannel method. The RunOutputLoop() method 36 | // processes data received on this channel, and returns after the Close() 37 | // method is called. 38 | type Output interface { 39 | GetOutputChannel() chan []byte 40 | RunOutputLoop() 41 | Close() 42 | } 43 | 44 | // A Logger prints a formatted log message to the destination of the 45 | // implementation's choice. A Logger may be provided for some Input and 46 | // Output implementations for visibility into their ReadInto() and 47 | // RunOutputLoop() loops. 48 | // 49 | // The result of log.New() satisfies the Logger interface. 50 | type Logger interface { 51 | Printf(format string, v ...interface{}) 52 | } 53 | 54 | type nullLogger struct{} 55 | 56 | func (n nullLogger) Printf(format string, v ...interface{}) {} 57 | -------------------------------------------------------------------------------- /FrameStreamOutput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014,2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "io" 21 | "os" 22 | ) 23 | 24 | // FrameStreamOutput implements a dnstap Output to an io.Writer. 25 | type FrameStreamOutput struct { 26 | outputChannel chan []byte 27 | wait chan bool 28 | w Writer 29 | log Logger 30 | } 31 | 32 | // NewFrameStreamOutput creates a FrameStreamOutput writing dnstap data to 33 | // the given io.Writer. 34 | func NewFrameStreamOutput(w io.Writer) (o *FrameStreamOutput, err error) { 35 | ow, err := NewWriter(w, nil) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return &FrameStreamOutput{ 40 | outputChannel: make(chan []byte, outputChannelSize), 41 | wait: make(chan bool), 42 | w: ow, 43 | log: nullLogger{}, 44 | }, nil 45 | } 46 | 47 | // NewFrameStreamOutputFromFilename creates a file with the name fname, 48 | // truncates it if it exists, and returns a FrameStreamOutput writing to 49 | // the newly created or truncated file. 50 | func NewFrameStreamOutputFromFilename(fname string) (o *FrameStreamOutput, err error) { 51 | if fname == "" || fname == "-" { 52 | return NewFrameStreamOutput(os.Stdout) 53 | } 54 | w, err := os.Create(fname) 55 | if err != nil { 56 | return 57 | } 58 | return NewFrameStreamOutput(w) 59 | } 60 | 61 | // SetLogger sets an alternate logger for the FrameStreamOutput. The default 62 | // is no logging. 63 | func (o *FrameStreamOutput) SetLogger(logger Logger) { 64 | o.log = logger 65 | } 66 | 67 | // GetOutputChannel returns the channel on which the FrameStreamOutput accepts 68 | // data. 69 | // 70 | // GetOutputData satisfies the dnstap Output interface. 71 | func (o *FrameStreamOutput) GetOutputChannel() chan []byte { 72 | return o.outputChannel 73 | } 74 | 75 | // RunOutputLoop processes data received on the channel returned by 76 | // GetOutputChannel, returning after the CLose method is called. 77 | // If there is an error writing to the Output's writer, RunOutputLoop() 78 | // returns, logging an error if a logger is configured with SetLogger() 79 | // 80 | // RunOutputLoop satisfies the dnstap Output interface. 81 | func (o *FrameStreamOutput) RunOutputLoop() { 82 | for frame := range o.outputChannel { 83 | if _, err := o.w.WriteFrame(frame); err != nil { 84 | o.log.Printf("FrameStreamOutput: Write error: %v, returning", err) 85 | close(o.wait) 86 | return 87 | } 88 | } 89 | close(o.wait) 90 | } 91 | 92 | // Close closes the channel returned from GetOutputChannel, and flushes 93 | // all pending output. 94 | // 95 | // Close satisifies the dnstap Output interface. 96 | func (o *FrameStreamOutput) Close() { 97 | close(o.outputChannel) 98 | <-o.wait 99 | o.w.Close() 100 | } 101 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/farsightsec/golang-framestream v0.3.0 h1:/spFQHucTle/ZIPkYqrfshQqPe2VQEzesH243TjIwqA= 2 | github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= 3 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 4 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 5 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 6 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 7 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 8 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 9 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 10 | github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= 11 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 12 | github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= 13 | github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 14 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 15 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= 16 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 17 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 18 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 19 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 20 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= 21 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 22 | golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 23 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 24 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 25 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= 27 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 28 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 29 | golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 30 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 31 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 32 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 33 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 34 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 35 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 36 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 37 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 38 | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= 39 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 40 | -------------------------------------------------------------------------------- /TextOutput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "bufio" 21 | "io" 22 | "os" 23 | 24 | "google.golang.org/protobuf/proto" 25 | ) 26 | 27 | // A TextFormatFunc renders a dnstap message into a human readable format. 28 | type TextFormatFunc func(*Dnstap) ([]byte, bool) 29 | 30 | // TextOutput implements a dnstap Output rendering dnstap data as text. 31 | type TextOutput struct { 32 | format TextFormatFunc 33 | outputChannel chan []byte 34 | wait chan bool 35 | writer *bufio.Writer 36 | log Logger 37 | } 38 | 39 | // NewTextOutput creates a TextOutput writing dnstap data to the given io.Writer 40 | // in the text format given by the TextFormatFunc format. 41 | func NewTextOutput(writer io.Writer, format TextFormatFunc) (o *TextOutput) { 42 | o = new(TextOutput) 43 | o.format = format 44 | o.outputChannel = make(chan []byte, outputChannelSize) 45 | o.writer = bufio.NewWriter(writer) 46 | o.wait = make(chan bool) 47 | return 48 | } 49 | 50 | // NewTextOutputFromFilename creates a TextOutput writing dnstap data to a 51 | // file with the given filename in the format given by format. If doAppend 52 | // is false, the file is truncated if it already exists, otherwise the file 53 | // is opened for appending. 54 | func NewTextOutputFromFilename(fname string, format TextFormatFunc, doAppend bool) (o *TextOutput, err error) { 55 | if fname == "" || fname == "-" { 56 | return NewTextOutput(os.Stdout, format), nil 57 | } 58 | var writer io.Writer 59 | if doAppend { 60 | writer, err = os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) 61 | } else { 62 | writer, err = os.Create(fname) 63 | } 64 | if err != nil { 65 | return 66 | } 67 | return NewTextOutput(writer, format), nil 68 | } 69 | 70 | // SetLogger configures a logger for error events in the TextOutput 71 | func (o *TextOutput) SetLogger(logger Logger) { 72 | o.log = logger 73 | } 74 | 75 | // GetOutputChannel returns the channel on which the TextOutput accepts dnstap data. 76 | // 77 | // GetOutputChannel satisfies the dnstap Output interface. 78 | func (o *TextOutput) GetOutputChannel() chan []byte { 79 | return o.outputChannel 80 | } 81 | 82 | // RunOutputLoop receives dnstap data sent on the output channel, formats it 83 | // with the configured TextFormatFunc, and writes it to the file or io.Writer 84 | // of the TextOutput. 85 | // 86 | // RunOutputLoop satisfies the dnstap Output interface. 87 | func (o *TextOutput) RunOutputLoop() { 88 | dt := &Dnstap{} 89 | for frame := range o.outputChannel { 90 | if err := proto.Unmarshal(frame, dt); err != nil { 91 | o.log.Printf("dnstap.TextOutput: proto.Unmarshal() failed: %s, returning", err) 92 | break 93 | } 94 | buf, ok := o.format(dt) 95 | if !ok { 96 | o.log.Printf("dnstap.TextOutput: text format function failed, returning") 97 | break 98 | } 99 | if _, err := o.writer.Write(buf); err != nil { 100 | o.log.Printf("dnstap.TextOutput: write error: %v, returning", err) 101 | break 102 | } 103 | o.writer.Flush() 104 | } 105 | close(o.wait) 106 | } 107 | 108 | // Close closes the output channel and returns when all pending data has been 109 | // written. 110 | // 111 | // Close satisfies the dnstap Output interface. 112 | func (o *TextOutput) Close() { 113 | close(o.outputChannel) 114 | <-o.wait 115 | o.writer.Flush() 116 | } 117 | -------------------------------------------------------------------------------- /FrameStreamInput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "io" 21 | "os" 22 | "time" 23 | ) 24 | 25 | // MaxPayloadSize sets the upper limit on input Dnstap payload sizes. If an Input 26 | // receives a Dnstap payload over this size limit, ReadInto will log an error and 27 | // return. 28 | // 29 | // EDNS0 and DNS over TCP use 2 octets for DNS message size, imposing a maximum 30 | // size of 65535 octets for the DNS message, which is the bulk of the data carried 31 | // in a Dnstap message. Protobuf encoding overhead and metadata with some size 32 | // guidance (e.g., identity and version being DNS strings, which have a maximum 33 | // length of 255) add up to less than 1KB. The default 96KiB size of the buffer 34 | // allows a bit over 30KB space for "extra" metadata. 35 | // 36 | var MaxPayloadSize uint32 = 96 * 1024 37 | 38 | // A FrameStreamInput reads dnstap data from an io.ReadWriter. 39 | type FrameStreamInput struct { 40 | wait chan bool 41 | reader Reader 42 | log Logger 43 | } 44 | 45 | // NewFrameStreamInput creates a FrameStreamInput reading data from the given 46 | // io.ReadWriter. If bi is true, the input will use the bidirectional 47 | // framestream protocol suitable for TCP and unix domain socket connections. 48 | func NewFrameStreamInput(r io.ReadWriter, bi bool) (input *FrameStreamInput, err error) { 49 | return NewFrameStreamInputTimeout(r, bi, 0) 50 | } 51 | 52 | // NewFrameStreamInputTimeout creates a FramestreamInput reading data from the 53 | // given io.ReadWriter with a timeout applied to reading and (for bidirectional 54 | // inputs) writing control messages. 55 | func NewFrameStreamInputTimeout(r io.ReadWriter, bi bool, timeout time.Duration) (input *FrameStreamInput, err error) { 56 | reader, err := NewReader(r, &ReaderOptions{ 57 | Bidirectional: bi, 58 | Timeout: timeout, 59 | }) 60 | 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | return &FrameStreamInput{ 66 | wait: make(chan bool), 67 | reader: reader, 68 | log: nullLogger{}, 69 | }, nil 70 | } 71 | 72 | // NewFrameStreamInputFromFilename creates a FrameStreamInput reading from 73 | // the named file. 74 | func NewFrameStreamInputFromFilename(fname string) (input *FrameStreamInput, err error) { 75 | file, err := os.Open(fname) 76 | if err != nil { 77 | return nil, err 78 | } 79 | return NewFrameStreamInput(file, false) 80 | } 81 | 82 | // SetLogger configures a logger for FrameStreamInput read error reporting. 83 | func (input *FrameStreamInput) SetLogger(logger Logger) { 84 | input.log = logger 85 | } 86 | 87 | // ReadInto reads data from the FrameStreamInput into the output channel. 88 | // 89 | // ReadInto satisfies the dnstap Input interface. 90 | func (input *FrameStreamInput) ReadInto(output chan []byte) { 91 | buf := make([]byte, MaxPayloadSize) 92 | for { 93 | n, err := input.reader.ReadFrame(buf) 94 | if err == nil { 95 | newbuf := make([]byte, n) 96 | copy(newbuf, buf) 97 | output <- newbuf 98 | continue 99 | } 100 | 101 | if err != io.EOF { 102 | input.log.Printf("FrameStreamInput: Read error: %v", err) 103 | } 104 | 105 | break 106 | } 107 | close(input.wait) 108 | } 109 | 110 | // Wait reeturns when ReadInto has finished. 111 | // 112 | // Wait satisfies the dnstap Input interface. 113 | func (input *FrameStreamInput) Wait() { 114 | <-input.wait 115 | } 116 | -------------------------------------------------------------------------------- /YamlFormat.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "net" 23 | "strconv" 24 | "strings" 25 | "time" 26 | 27 | "github.com/miekg/dns" 28 | ) 29 | 30 | const yamlTimeFormat = "2006-01-02 15:04:05.999999999" 31 | 32 | func yamlConvertMessage(m *Message, s *bytes.Buffer) { 33 | s.WriteString(fmt.Sprint(" type: ", m.Type, "\n")) 34 | 35 | if m.QueryTimeSec != nil && m.QueryTimeNsec != nil { 36 | t := time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC() 37 | s.WriteString(fmt.Sprint(" query_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) 38 | } 39 | 40 | if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil { 41 | t := time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC() 42 | s.WriteString(fmt.Sprint(" response_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) 43 | } 44 | 45 | if m.SocketFamily != nil { 46 | s.WriteString(fmt.Sprint(" socket_family: ", m.SocketFamily, "\n")) 47 | } 48 | 49 | if m.SocketProtocol != nil { 50 | s.WriteString(fmt.Sprint(" socket_protocol: ", m.SocketProtocol, "\n")) 51 | } 52 | 53 | if m.QueryAddress != nil { 54 | s.WriteString(fmt.Sprint(" query_address: ", net.IP(m.QueryAddress), "\n")) 55 | } 56 | 57 | if m.ResponseAddress != nil { 58 | s.WriteString(fmt.Sprint(" response_address: ", net.IP(m.ResponseAddress), "\n")) 59 | } 60 | 61 | if m.QueryPort != nil { 62 | s.WriteString(fmt.Sprint(" query_port: ", *m.QueryPort, "\n")) 63 | } 64 | 65 | if m.ResponsePort != nil { 66 | s.WriteString(fmt.Sprint(" response_port: ", *m.ResponsePort, "\n")) 67 | } 68 | 69 | if m.QueryZone != nil { 70 | name, _, err := dns.UnpackDomainName(m.QueryZone, 0) 71 | if err != nil { 72 | fmt.Fprintf(s, " # query_zone: parse failed: %v\n", err) 73 | } else { 74 | s.WriteString(fmt.Sprint(" query_zone: ", strconv.Quote(name), "\n")) 75 | } 76 | } 77 | 78 | if m.QueryMessage != nil { 79 | msg := new(dns.Msg) 80 | err := msg.Unpack(m.QueryMessage) 81 | if err != nil { 82 | fmt.Fprintf(s, " # query_message: parse failed: %v\n", err) 83 | } else { 84 | s.WriteString(" query_message: |\n") 85 | s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") 86 | } 87 | } 88 | if m.ResponseMessage != nil { 89 | msg := new(dns.Msg) 90 | err := msg.Unpack(m.ResponseMessage) 91 | if err != nil { 92 | fmt.Fprintf(s, " # response_message: parse failed: %v\n", err) 93 | } else { 94 | s.WriteString(" response_message: |\n") 95 | s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") 96 | } 97 | } 98 | s.WriteString("---\n") 99 | } 100 | 101 | // YamlFormat renders a dnstap message in YAML format. Any encapsulated DNS 102 | // messages are rendered as strings in a format similar to 'dig' output. 103 | func YamlFormat(dt *Dnstap) (out []byte, ok bool) { 104 | var s bytes.Buffer 105 | 106 | s.WriteString(fmt.Sprint("type: ", dt.Type, "\n")) 107 | if dt.Identity != nil { 108 | s.WriteString(fmt.Sprint("identity: ", strconv.Quote(string(dt.Identity)), "\n")) 109 | } 110 | if dt.Version != nil { 111 | s.WriteString(fmt.Sprint("version: ", strconv.Quote(string(dt.Version)), "\n")) 112 | } 113 | if *dt.Type == Dnstap_MESSAGE { 114 | s.WriteString("message:\n") 115 | yamlConvertMessage(dt.Message, &s) 116 | } 117 | return s.Bytes(), true 118 | } 119 | -------------------------------------------------------------------------------- /FrameStreamSockInput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "fmt" 21 | "net" 22 | "os" 23 | "time" 24 | ) 25 | 26 | // A FrameStreamSockInput collects dnstap data from one or more clients of 27 | // a listening socket. 28 | type FrameStreamSockInput struct { 29 | wait chan bool 30 | listener net.Listener 31 | timeout time.Duration 32 | log Logger 33 | } 34 | 35 | // NewFrameStreamSockInput creates a FrameStreamSockInput collecting dnstap 36 | // data from clients which connect to the given listener. 37 | func NewFrameStreamSockInput(listener net.Listener) (input *FrameStreamSockInput) { 38 | input = new(FrameStreamSockInput) 39 | input.listener = listener 40 | input.log = &nullLogger{} 41 | return 42 | } 43 | 44 | // SetTimeout sets the timeout for reading the initial handshake and writing 45 | // response control messages to clients of the FrameStreamSockInput's listener. 46 | // 47 | // The timeout is effective only for connections accepted after the call to 48 | // SetTimeout. 49 | func (input *FrameStreamSockInput) SetTimeout(timeout time.Duration) { 50 | input.timeout = timeout 51 | } 52 | 53 | // SetLogger configures a logger for the FrameStreamSockInput. 54 | func (input *FrameStreamSockInput) SetLogger(logger Logger) { 55 | input.log = logger 56 | } 57 | 58 | // NewFrameStreamSockInputFromPath creates a unix domain socket at the 59 | // given socketPath and returns a FrameStreamSockInput collecting dnstap 60 | // data from clients connecting to this socket. 61 | // 62 | // If a socket or other file already exists at socketPath, 63 | // NewFrameStreamSockInputFromPath removes it before creating the socket. 64 | func NewFrameStreamSockInputFromPath(socketPath string) (input *FrameStreamSockInput, err error) { 65 | os.Remove(socketPath) 66 | listener, err := net.Listen("unix", socketPath) 67 | if err != nil { 68 | return 69 | } 70 | return NewFrameStreamSockInput(listener), nil 71 | } 72 | 73 | // ReadInto accepts connections to the FrameStreamSockInput's listening 74 | // socket and sends all dnstap data read from these connections to the 75 | // output channel. 76 | // 77 | // ReadInto satisfies the dnstap Input interface. 78 | func (input *FrameStreamSockInput) ReadInto(output chan []byte) { 79 | var n uint64 80 | for { 81 | conn, err := input.listener.Accept() 82 | if err != nil { 83 | input.log.Printf("%s: accept failed: %v\n", 84 | input.listener.Addr(), 85 | err) 86 | continue 87 | } 88 | n++ 89 | origin := "" 90 | switch conn.RemoteAddr().Network() { 91 | case "tcp", "tcp4", "tcp6": 92 | origin = fmt.Sprintf(" from %s", conn.RemoteAddr()) 93 | } 94 | i, err := NewFrameStreamInputTimeout(conn, true, input.timeout) 95 | if err != nil { 96 | input.log.Printf("%s: connection %d: open input%s failed: %v", 97 | conn.LocalAddr(), n, origin, err) 98 | continue 99 | } 100 | input.log.Printf("%s: accepted connection %d%s", 101 | conn.LocalAddr(), n, origin) 102 | i.SetLogger(input.log) 103 | go func(cn uint64) { 104 | i.ReadInto(output) 105 | input.log.Printf("%s: closed connection %d%s", 106 | conn.LocalAddr(), cn, origin) 107 | }(n) 108 | } 109 | } 110 | 111 | // Wait satisfies the dnstap Input interface. 112 | // 113 | // The FrameSTreamSocketInput Wait method never returns, because the 114 | // corresponding Readinto method also never returns. 115 | func (input *FrameStreamSockInput) Wait() { 116 | select {} 117 | } 118 | -------------------------------------------------------------------------------- /dnstap/fileoutput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "os" 23 | "os/signal" 24 | "syscall" 25 | 26 | dnstap "github.com/dnstap/golang-dnstap" 27 | ) 28 | 29 | // Output channel buffer size value from main dnstap package. 30 | const outputChannelSize = 32 31 | 32 | // 33 | // A fileOutput implements a dnstap.Output which writes frames to a file 34 | // and closes and reopens the file on SIGHUP. 35 | // 36 | // Data frames are written in binary fstrm format unless a text formatting 37 | // function (dnstp.TextFormatFunc) is given or the filename is blank or "-". 38 | // In the latter case, data is written in compact (quiet) text format unless 39 | // an alternate text format is given on the assumption that stdout is a terminal. 40 | // 41 | type fileOutput struct { 42 | formatter dnstap.TextFormatFunc 43 | filename string 44 | doAppend bool 45 | output dnstap.Output 46 | data chan []byte 47 | done chan struct{} 48 | } 49 | 50 | func openOutputFile(filename string, formatter dnstap.TextFormatFunc, doAppend bool) (o dnstap.Output, err error) { 51 | var fso *dnstap.FrameStreamOutput 52 | var to *dnstap.TextOutput 53 | if formatter == nil { 54 | if filename == "-" || filename == "" { 55 | to = dnstap.NewTextOutput(os.Stdout, dnstap.TextFormat) 56 | to.SetLogger(logger) 57 | return to, nil 58 | } 59 | fso, err = dnstap.NewFrameStreamOutputFromFilename(filename) 60 | if err == nil { 61 | fso.SetLogger(logger) 62 | return fso, nil 63 | } 64 | } else { 65 | if filename == "-" || filename == "" { 66 | if doAppend { 67 | return nil, errors.New("cannot append to stdout (-)") 68 | } 69 | to = dnstap.NewTextOutput(os.Stdout, formatter) 70 | to.SetLogger(logger) 71 | return to, nil 72 | } 73 | to, err = dnstap.NewTextOutputFromFilename(filename, formatter, doAppend) 74 | if err == nil { 75 | to.SetLogger(logger) 76 | } 77 | return to, nil 78 | } 79 | return 80 | } 81 | 82 | func newFileOutput(filename string, formatter dnstap.TextFormatFunc, doAppend bool) (*fileOutput, error) { 83 | o, err := openOutputFile(filename, formatter, doAppend) 84 | if err != nil { 85 | return nil, err 86 | } 87 | return &fileOutput{ 88 | formatter: formatter, 89 | filename: filename, 90 | doAppend: doAppend, 91 | output: o, 92 | data: make(chan []byte, outputChannelSize), 93 | done: make(chan struct{}), 94 | }, nil 95 | } 96 | 97 | func (fo *fileOutput) GetOutputChannel() chan []byte { 98 | return fo.data 99 | } 100 | 101 | func (fo *fileOutput) Close() { 102 | close(fo.data) 103 | <-fo.done 104 | } 105 | 106 | func (fo *fileOutput) RunOutputLoop() { 107 | sigch := make(chan os.Signal, 1) 108 | signal.Notify(sigch, os.Interrupt, syscall.SIGHUP) 109 | o := fo.output 110 | go o.RunOutputLoop() 111 | defer func() { 112 | o.Close() 113 | close(fo.done) 114 | }() 115 | for { 116 | select { 117 | case b, ok := <-fo.data: 118 | if !ok { 119 | return 120 | } 121 | o.GetOutputChannel() <- b 122 | case sig := <-sigch: 123 | if sig == syscall.SIGHUP { 124 | o.Close() 125 | newo, err := openOutputFile(fo.filename, fo.formatter, fo.doAppend) 126 | if err != nil { 127 | fmt.Fprintf(os.Stderr, 128 | "dnstap: Error: failed to reopen %s: %v\n", 129 | fo.filename, err) 130 | os.Exit(1) 131 | } 132 | o = newo 133 | go o.RunOutputLoop() 134 | continue 135 | } 136 | os.Exit(0) 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /FrameStreamSockOutput.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "net" 21 | "time" 22 | ) 23 | 24 | // A FrameStreamSockOutput manages a socket connection and sends dnstap 25 | // data over a framestream connection on that socket. 26 | type FrameStreamSockOutput struct { 27 | address net.Addr 28 | outputChannel chan []byte 29 | wait chan bool 30 | wopt SocketWriterOptions 31 | } 32 | 33 | // NewFrameStreamSockOutput creates a FrameStreamSockOutput manaaging a 34 | // connection to the given address. 35 | func NewFrameStreamSockOutput(address net.Addr) (*FrameStreamSockOutput, error) { 36 | return &FrameStreamSockOutput{ 37 | address: address, 38 | outputChannel: make(chan []byte, outputChannelSize), 39 | wait: make(chan bool), 40 | wopt: SocketWriterOptions{ 41 | FlushTimeout: 5 * time.Second, 42 | RetryInterval: 10 * time.Second, 43 | Dialer: &net.Dialer{ 44 | Timeout: 30 * time.Second, 45 | }, 46 | Logger: &nullLogger{}, 47 | }, 48 | }, nil 49 | } 50 | 51 | // SetTimeout sets the write timeout for data and control messages and the 52 | // read timeout for handshake responses on the FrameStreamSockOutput's 53 | // connection. The default timeout is zero, for no timeout. 54 | func (o *FrameStreamSockOutput) SetTimeout(timeout time.Duration) { 55 | o.wopt.Timeout = timeout 56 | } 57 | 58 | // SetFlushTimeout sets the maximum time data will be kept in the output 59 | // buffer. 60 | // 61 | // The default flush timeout is five seconds. 62 | func (o *FrameStreamSockOutput) SetFlushTimeout(timeout time.Duration) { 63 | o.wopt.FlushTimeout = timeout 64 | } 65 | 66 | // SetRetryInterval specifies how long the FrameStreamSockOutput will wait 67 | // before re-establishing a failed connection. The default retry interval 68 | // is 10 seconds. 69 | func (o *FrameStreamSockOutput) SetRetryInterval(retry time.Duration) { 70 | o.wopt.RetryInterval = retry 71 | } 72 | 73 | // SetDialer replaces the default net.Dialer for re-establishing the 74 | // the FrameStreamSockOutput connection. This can be used to set the 75 | // timeout for connection establishment and enable keepalives 76 | // new connections. 77 | // 78 | // FrameStreamSockOutput uses a default dialer with a 30 second 79 | // timeout. 80 | func (o *FrameStreamSockOutput) SetDialer(dialer *net.Dialer) { 81 | o.wopt.Dialer = dialer 82 | } 83 | 84 | // SetLogger configures FrameStreamSockOutput to log through the given 85 | // Logger. 86 | func (o *FrameStreamSockOutput) SetLogger(logger Logger) { 87 | o.wopt.Logger = logger 88 | } 89 | 90 | // GetOutputChannel returns the channel on which the 91 | // FrameStreamSockOutput accepts data. 92 | // 93 | // GetOutputChannel satisifes the dnstap Output interface. 94 | func (o *FrameStreamSockOutput) GetOutputChannel() chan []byte { 95 | return o.outputChannel 96 | } 97 | 98 | // RunOutputLoop reads data from the output channel and sends it over 99 | // a connections to the FrameStreamSockOutput's address, establishing 100 | // the connection as needed. 101 | // 102 | // RunOutputLoop satisifes the dnstap Output interface. 103 | func (o *FrameStreamSockOutput) RunOutputLoop() { 104 | w := NewSocketWriter(o.address, &o.wopt) 105 | 106 | for b := range o.outputChannel { 107 | // w is of type *SocketWriter, whose Write implementation 108 | // handles all errors by retrying the connection. 109 | w.WriteFrame(b) 110 | } 111 | 112 | w.Close() 113 | close(o.wait) 114 | return 115 | } 116 | 117 | // Close shuts down the FrameStreamSockOutput's output channel and returns 118 | // after all pending data has been flushed and the connection has been closed. 119 | // 120 | // Close satisifes the dnstap Output interface 121 | func (o *FrameStreamSockOutput) Close() { 122 | close(o.outputChannel) 123 | <-o.wait 124 | } 125 | -------------------------------------------------------------------------------- /JsonFormat.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package dnstap 16 | 17 | import ( 18 | "bytes" 19 | "encoding/json" 20 | "fmt" 21 | "net" 22 | "time" 23 | 24 | "github.com/miekg/dns" 25 | ) 26 | 27 | type jsonTime time.Time 28 | 29 | func (jt *jsonTime) MarshalJSON() ([]byte, error) { 30 | stamp := time.Time(*jt).Format(time.RFC3339Nano) 31 | return []byte(fmt.Sprintf("\"%s\"", stamp)), nil 32 | } 33 | 34 | type jsonDnstap struct { 35 | Type string `json:"type"` 36 | Identity string `json:"identity,omitempty"` 37 | Version string `json:"version,omitempty"` 38 | Message jsonMessage `json:"message"` 39 | } 40 | 41 | type jsonMessage struct { 42 | Type string `json:"type"` 43 | QueryTime *jsonTime `json:"query_time,omitempty"` 44 | ResponseTime *jsonTime `json:"response_time,omitempty"` 45 | SocketFamily string `json:"socket_family,omitempty"` 46 | SocketProtocol string `json:"socket_protocol,omitempty"` 47 | QueryAddress *net.IP `json:"query_address,omitempty"` 48 | ResponseAddress *net.IP `json:"response_address,omitempty"` 49 | QueryPort uint32 `json:"query_port,omitempty"` 50 | ResponsePort uint32 `json:"response_port,omitempty"` 51 | QueryZone string `json:"query_zone,omitempty"` 52 | QueryMessage string `json:"query_message,omitempty"` 53 | ResponseMessage string `json:"response_message,omitempty"` 54 | } 55 | 56 | func convertJSONMessage(m *Message) jsonMessage { 57 | jMsg := jsonMessage{ 58 | Type: fmt.Sprint(m.Type), 59 | SocketFamily: fmt.Sprint(m.SocketFamily), 60 | SocketProtocol: fmt.Sprint(m.SocketProtocol), 61 | } 62 | 63 | if m.QueryTimeSec != nil && m.QueryTimeNsec != nil { 64 | qt := jsonTime(time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC()) 65 | jMsg.QueryTime = &qt 66 | } 67 | 68 | if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil { 69 | rt := jsonTime(time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC()) 70 | jMsg.ResponseTime = &rt 71 | } 72 | 73 | if m.QueryAddress != nil { 74 | qa := net.IP(m.QueryAddress) 75 | jMsg.QueryAddress = &qa 76 | } 77 | 78 | if m.ResponseAddress != nil { 79 | ra := net.IP(m.ResponseAddress) 80 | jMsg.ResponseAddress = &ra 81 | } 82 | 83 | if m.QueryPort != nil { 84 | jMsg.QueryPort = *m.QueryPort 85 | } 86 | 87 | if m.ResponsePort != nil { 88 | jMsg.ResponsePort = *m.ResponsePort 89 | } 90 | 91 | if m.QueryZone != nil { 92 | name, _, err := dns.UnpackDomainName(m.QueryZone, 0) 93 | if err != nil { 94 | jMsg.QueryZone = fmt.Sprintf("parse failed: %v", err) 95 | } else { 96 | jMsg.QueryZone = string(name) 97 | } 98 | } 99 | 100 | if m.QueryMessage != nil { 101 | msg := new(dns.Msg) 102 | err := msg.Unpack(m.QueryMessage) 103 | if err != nil { 104 | jMsg.QueryMessage = fmt.Sprintf("parse failed: %v", err) 105 | } else { 106 | jMsg.QueryMessage = msg.String() 107 | } 108 | } 109 | 110 | if m.ResponseMessage != nil { 111 | msg := new(dns.Msg) 112 | err := msg.Unpack(m.ResponseMessage) 113 | if err != nil { 114 | jMsg.ResponseMessage = fmt.Sprintf("parse failed: %v", err) 115 | } else { 116 | jMsg.ResponseMessage = msg.String() 117 | } 118 | } 119 | return jMsg 120 | } 121 | 122 | // JSONFormat renders a Dnstap message in JSON format. Any encapsulated 123 | // DNS messages are rendered as strings in a format similar to 'dig' output. 124 | func JSONFormat(dt *Dnstap) (out []byte, ok bool) { 125 | var s bytes.Buffer 126 | 127 | j, err := json.Marshal(jsonDnstap{ 128 | Type: fmt.Sprint(dt.Type), 129 | Identity: string(dt.Identity), 130 | Version: string(dt.Version), 131 | Message: convertJSONMessage(dt.Message), 132 | }) 133 | if err != nil { 134 | return nil, false 135 | } 136 | 137 | s.WriteString(string(j) + "\n") 138 | 139 | return s.Bytes(), true 140 | } 141 | -------------------------------------------------------------------------------- /QuietTextFormat.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "net" 23 | "strconv" 24 | "time" 25 | 26 | "github.com/miekg/dns" 27 | ) 28 | 29 | const quietTimeFormat = "15:04:05" 30 | 31 | func textConvertTime(s *bytes.Buffer, secs *uint64, nsecs *uint32) { 32 | if secs != nil { 33 | s.WriteString(time.Unix(int64(*secs), 0).Format(quietTimeFormat)) 34 | } else { 35 | s.WriteString("??:??:??") 36 | } 37 | if nsecs != nil { 38 | s.WriteString(fmt.Sprintf(".%06d", *nsecs/1000)) 39 | } else { 40 | s.WriteString(".??????") 41 | } 42 | } 43 | 44 | func textConvertIP(s *bytes.Buffer, ip []byte) { 45 | if ip != nil { 46 | s.WriteString(net.IP(ip).String()) 47 | } else { 48 | s.WriteString("MISSING_ADDRESS") 49 | } 50 | } 51 | 52 | func textConvertMessage(m *Message, s *bytes.Buffer) { 53 | isQuery := false 54 | printQueryAddress := false 55 | 56 | switch *m.Type { 57 | case Message_CLIENT_QUERY, 58 | Message_RESOLVER_QUERY, 59 | Message_AUTH_QUERY, 60 | Message_FORWARDER_QUERY, 61 | Message_TOOL_QUERY, 62 | Message_UPDATE_QUERY: 63 | isQuery = true 64 | case Message_CLIENT_RESPONSE, 65 | Message_RESOLVER_RESPONSE, 66 | Message_AUTH_RESPONSE, 67 | Message_FORWARDER_RESPONSE, 68 | Message_TOOL_RESPONSE, 69 | Message_UPDATE_RESPONSE: 70 | isQuery = false 71 | default: 72 | s.WriteString("[unhandled Message.Type]\n") 73 | return 74 | } 75 | 76 | if isQuery { 77 | textConvertTime(s, m.QueryTimeSec, m.QueryTimeNsec) 78 | } else { 79 | textConvertTime(s, m.ResponseTimeSec, m.ResponseTimeNsec) 80 | } 81 | s.WriteString(" ") 82 | 83 | switch *m.Type { 84 | case Message_CLIENT_QUERY, 85 | Message_CLIENT_RESPONSE: 86 | { 87 | s.WriteString("C") 88 | } 89 | case Message_RESOLVER_QUERY, 90 | Message_RESOLVER_RESPONSE: 91 | { 92 | s.WriteString("R") 93 | } 94 | case Message_AUTH_QUERY, 95 | Message_AUTH_RESPONSE: 96 | { 97 | s.WriteString("A") 98 | } 99 | case Message_FORWARDER_QUERY, 100 | Message_FORWARDER_RESPONSE: 101 | { 102 | s.WriteString("F") 103 | } 104 | case Message_STUB_QUERY, 105 | Message_STUB_RESPONSE: 106 | { 107 | s.WriteString("S") 108 | } 109 | case Message_TOOL_QUERY, 110 | Message_TOOL_RESPONSE: 111 | { 112 | s.WriteString("T") 113 | } 114 | case Message_UPDATE_QUERY, 115 | Message_UPDATE_RESPONSE: 116 | { 117 | s.WriteString("U") 118 | } 119 | } 120 | 121 | if isQuery { 122 | s.WriteString("Q ") 123 | } else { 124 | s.WriteString("R ") 125 | } 126 | 127 | switch *m.Type { 128 | case Message_CLIENT_QUERY, 129 | Message_CLIENT_RESPONSE, 130 | Message_AUTH_QUERY, 131 | Message_AUTH_RESPONSE: 132 | printQueryAddress = true 133 | } 134 | 135 | if printQueryAddress { 136 | textConvertIP(s, m.QueryAddress) 137 | } else { 138 | textConvertIP(s, m.ResponseAddress) 139 | } 140 | s.WriteString(" ") 141 | 142 | if m.SocketProtocol != nil { 143 | s.WriteString(m.SocketProtocol.String()) 144 | } 145 | s.WriteString(" ") 146 | 147 | var err error 148 | msg := new(dns.Msg) 149 | if isQuery { 150 | s.WriteString(strconv.Itoa(len(m.QueryMessage))) 151 | s.WriteString("b ") 152 | err = msg.Unpack(m.QueryMessage) 153 | } else { 154 | s.WriteString(strconv.Itoa(len(m.ResponseMessage))) 155 | s.WriteString("b ") 156 | err = msg.Unpack(m.ResponseMessage) 157 | } 158 | 159 | if err != nil || len(msg.Question) == 0 { 160 | s.WriteString("X ") 161 | } else { 162 | s.WriteString("\"" + msg.Question[0].Name + "\" ") 163 | s.WriteString(dns.Class(msg.Question[0].Qclass).String() + " ") 164 | s.WriteString(dns.Type(msg.Question[0].Qtype).String()) 165 | } 166 | 167 | s.WriteString("\n") 168 | } 169 | 170 | // TextFormat renders a dnstap message in a compact human-readable text 171 | // form. 172 | func TextFormat(dt *Dnstap) (out []byte, ok bool) { 173 | var s bytes.Buffer 174 | 175 | if *dt.Type == Dnstap_MESSAGE { 176 | textConvertMessage(dt.Message, &s) 177 | return s.Bytes(), true 178 | } 179 | 180 | return nil, false 181 | } 182 | -------------------------------------------------------------------------------- /dnstap/dnstap.8: -------------------------------------------------------------------------------- 1 | .TH dnstap 8 2 | 3 | .SH NAME 4 | 5 | dnstap \- Capture, display, and relay Dnstap data. 6 | 7 | .SH SYNOPSIS 8 | 9 | .B dnstap [ -u \fIsocket-path\fB [ -u \fIsocket2-path\fB ... ] ] 10 | .br 11 | .B " [ -l \fIhost:port\fB [ -l \fIhost2:port2\fB ... ] ]" 12 | .br 13 | .B " [ -r \fIfile\fB [ -r \fIfile2\fB ... ] ]" 14 | .br 15 | .B " [ -U \fIsocket-path\fB [ -U \fIsocket2-path\fB ... ] ]" 16 | .br 17 | .B " [ -T \fIhost:port\fB [ -T \fIhost2:port2\fB ... ] ]" 18 | .br 19 | .B " [ -w \fIfile\fB ] [ -q | -y | -j ] [-a]" 20 | .br 21 | .B " [ -t \fItimeout\fB ]" 22 | .br 23 | 24 | .SH DESCRIPTION 25 | 26 | .B dnstap 27 | reads data in the Dnstap export format from Frame Streams files or 28 | receives data on Frame Streams connections to TCP/IP or unix domain 29 | socket addresses. 30 | .B dnstap 31 | can display this data in a compact text (the default), JSON, or YAML 32 | formats. It can also save data to a file in display or Frame Streams 33 | binary format, or relay the data to other Dnstap processes over unix 34 | domain socket or TCP/IP connections. 35 | 36 | .SH OPTIONS 37 | 38 | .TP 39 | .B -a 40 | When opening an file (\fB-w\fR) for text format output 41 | (\fB-j\fR, \fB-q\fR, or \fB-y\fR), append to the file rather 42 | truncating. 43 | 44 | .B -a 45 | does not apply when writing binary Frame Streams data to a file. 46 | 47 | .TP 48 | .B -j 49 | Write data in JSON format. Encapsulated DNS messages are 50 | rendered in text form similar to the output of \fBdig(1)\fR. 51 | 52 | At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be 53 | given. 54 | 55 | .TP 56 | .B -l \fIhost:port\fR 57 | Listen for Dnstap data on TCP/IP port \fBport\fR on address \fIhost\fR. 58 | 59 | The \fB-l\fR option may be given multiple times to listen on multiple 60 | addresses. 61 | 62 | At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given. 63 | 64 | .TP 65 | .B -q 66 | Write or display data in compact (quiet) text format. 67 | 68 | At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be given. 69 | 70 | .TP 71 | .B -r \fIfile\fR 72 | Read Dnstap data from the given \fIfile\fR. The \fB-r\fR option 73 | may be given multiple times to read from multiple files. 74 | 75 | At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given. 76 | 77 | .TP 78 | .B -T \fIhost:port\fR 79 | Relay Dnstap data over a TCP/IP connection to \fIhost:port\fR. 80 | \fBdnstap\fR will establish or re-establish this connection as needed. 81 | 82 | The \fB-T\fR option may be given multiple times to relay Dnstap data 83 | to multiple addresses. 84 | 85 | .TP 86 | .B -t \fItimeout\fR 87 | Apply i/o \fItimeout\fR to TCP/IP and unix domain socket 88 | connections. \fItimeout\fR is given as a number followed by a unit 89 | abbreviation (e.g., \fIms\fR for milliseconds, \fIs\fR for seconds, 90 | \fIm\fR for minutes). 91 | 92 | .TP 93 | .B -u \fIsocket-path\fR 94 | Listen for Dnstap data on the unix domain socket at 95 | \fIsocket-path\fR. \fBdnstap\fR will remove any file or socket 96 | \fIsocket-path\fR before listening. 97 | 98 | The \fB-u\fR option may be given multiple times to listen on multiple 99 | socket paths. 100 | 101 | At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given. 102 | 103 | .TP 104 | .B -U \fIsocket-path\fR 105 | Relay Dnstap data over a unix domain socket connection to 106 | \fIsocket-path\fR. \fBdnstap\fR will establish or re-establish this 107 | connection as needed. 108 | 109 | The \fB-U\fR option may be given multiple times to relay Dnstap data to 110 | multiple socket paths. 111 | 112 | 113 | .TP 114 | .B -w \fIfile\fR 115 | Write Dnstap data to \fIfile\fR. 116 | 117 | If \fIfile\fR is "-" or no \fB-w\fR, \fB-T\fR, or \fB-U\fR output 118 | options are present, data will be written to standard output in quiet 119 | text format (\fB-q\fR), unless the YAML or JSON format is specified 120 | with the \fB-y\fR or \fB-j\fR options, respectively. 121 | 122 | If \fIfile\fR is a filename other than "-", Dnstap data is written to the 123 | named file in Frame Streams binary format by default, unless quiet text, 124 | JSON, or YAML formats are specified. 125 | 126 | .B dnstap 127 | will reopen \fIfile\fR on \fBSIGHUP\fR, for file rotation purposes. 128 | 129 | 130 | .TP 131 | .B -y 132 | Write Dnstap output in YAML format. Encapsulated DNS messages are rendered in text 133 | form similar to the output of \fBdig(1)\fR. 134 | 135 | At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be given. 136 | 137 | 138 | .SH EXAMPLES 139 | 140 | Listen for Dnstap data from a local name server and print quiet text format 141 | to standard output. 142 | 143 | .nf 144 | dnstap -u /var/named/dnstap.sock 145 | .fi 146 | 147 | Listen for Dnstap data from a local name server, save a local binary copy, and 148 | relay it to a remote host over TCP. 149 | 150 | .nf 151 | dnstap -u /usr/local/unbound/dnstap.sock -w dnstap.fstrm \\ 152 | -T dns-admin.example.com:5353 153 | .fi 154 | 155 | .SH SEE ALSO 156 | 157 | .B dig(1) 158 | -------------------------------------------------------------------------------- /sock_test.go: -------------------------------------------------------------------------------- 1 | package dnstap 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | type testLogger struct{ *testing.T } 12 | 13 | func (t *testLogger) Printf(format string, v ...interface{}) { 14 | t.Helper() 15 | t.Logf(format, v...) 16 | } 17 | 18 | func dialAndSend(t *testing.T, network, address string) *FrameStreamSockOutput { 19 | var addr net.Addr 20 | var err error 21 | switch network { 22 | case "unix": 23 | addr, err = net.ResolveUnixAddr(network, address) 24 | case "tcp", "tcp4", "tcp6": 25 | addr, err = net.ResolveTCPAddr(network, address) 26 | default: 27 | err = fmt.Errorf("invalid network %s", network) 28 | } 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | out, err := NewFrameStreamSockOutput(addr) 34 | if err != nil { 35 | t.Fatal(err) 36 | } 37 | 38 | out.SetDialer(&net.Dialer{Timeout: time.Second}) 39 | out.SetTimeout(time.Second) 40 | out.SetFlushTimeout(100 * time.Millisecond) 41 | out.SetRetryInterval(time.Second) 42 | out.SetLogger(&testLogger{t}) 43 | 44 | go out.RunOutputLoop() 45 | <-time.After(500 * time.Millisecond) 46 | out.GetOutputChannel() <- []byte("frame") 47 | return out 48 | } 49 | 50 | func readOne(t *testing.T, out chan []byte) { 51 | select { 52 | case <-out: 53 | case <-time.After(time.Second): 54 | t.Fatal("timed out waiting for frame") 55 | } 56 | } 57 | 58 | // Test if dnstap can accept multiple connections on the socket 59 | func TestMultiConn(t *testing.T) { 60 | in, err := NewFrameStreamSockInputFromPath("dnstap.sock") 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | 65 | defer os.Remove("dnstap.sock") 66 | 67 | in.SetLogger(&testLogger{t}) 68 | out := make(chan []byte) 69 | go in.ReadInto(out) 70 | 71 | // send two framestream messages on different connections 72 | defer dialAndSend(t, "unix", "dnstap.sock").Close() 73 | defer dialAndSend(t, "unix", "dnstap.sock").Close() 74 | 75 | readOne(t, out) 76 | readOne(t, out) 77 | } 78 | 79 | func TestReconnect(t *testing.T) { 80 | // Find an open port on localhost by opening a listener on an 81 | // unspecified port, querying its address, then closing it. 82 | l, err := net.Listen("tcp", "localhost:0") 83 | if err != nil { 84 | t.Fatal(err) 85 | } 86 | laddr := l.Addr() 87 | l.Close() 88 | 89 | defer dialAndSend(t, laddr.Network(), laddr.String()).Close() 90 | defer dialAndSend(t, laddr.Network(), laddr.String()).Close() 91 | time.Sleep(1500 * time.Millisecond) 92 | l, err = net.Listen(laddr.Network(), laddr.String()) 93 | if err != nil { 94 | t.Fatal(err) 95 | } 96 | 97 | in := NewFrameStreamSockInput(l) 98 | in.SetLogger(&testLogger{t}) 99 | out := make(chan []byte) 100 | go in.ReadInto(out) 101 | readOne(t, out) 102 | readOne(t, out) 103 | } 104 | 105 | func BenchmarkConnectUnidirectional(b *testing.B) { 106 | b.StopTimer() 107 | l, err := net.Listen("tcp", "localhost:0") 108 | if err != nil { 109 | b.Fatal(err) 110 | } 111 | 112 | // read from tcp socket into outch 113 | outch := make(chan []byte, 32) 114 | go func() { 115 | // wait for connection 116 | s, err := l.Accept() 117 | if err != nil { 118 | b.Error(err) 119 | close(outch) 120 | return 121 | } 122 | 123 | // start rewriter 124 | in, err := NewFrameStreamInput(s, false) 125 | if err != nil { 126 | b.Error(err) 127 | close(outch) 128 | return 129 | } 130 | 131 | // read ASAP into outch 132 | in.ReadInto(outch) 133 | close(outch) 134 | }() 135 | 136 | // read from outch exactly b.N frames 137 | // this is separate from the above, because the process of rewriting tcp into outch 138 | // must run in parallel with reading b.N frames from outch 139 | readDone := make(chan struct{}) 140 | go func() { 141 | // wait for the first frame before starting the timer 142 | <-outch 143 | i := 1 144 | 145 | b.StartTimer() 146 | for _ = range outch { 147 | i++ 148 | } 149 | if i != b.N { 150 | b.Error("invalid frame count") 151 | } 152 | close(readDone) 153 | }() 154 | 155 | // connect to tcp socket and start the output loop 156 | c, err := net.Dial(l.Addr().Network(), l.Addr().String()) 157 | if err != nil { 158 | b.Fatal(err) 159 | } 160 | out, err := NewFrameStreamOutput(c) 161 | if err != nil { 162 | b.Fatal(err) 163 | } 164 | go out.RunOutputLoop() 165 | 166 | // write to the output channel exactly b.N frames 167 | for i := 0; i < b.N; i++ { 168 | out.GetOutputChannel() <- []byte("frame") 169 | } 170 | out.Close() 171 | 172 | // wait for the reader 173 | <-readDone 174 | } 175 | 176 | func BenchmarkConnectBidirectional(b *testing.B) { 177 | b.StopTimer() 178 | l, err := net.Listen("tcp", "localhost:0") 179 | if err != nil { 180 | b.Fatal(err) 181 | } 182 | 183 | // start an infinite tcp socket reader 184 | in := NewFrameStreamSockInput(l) 185 | outch := make(chan []byte, 32) 186 | go in.ReadInto(outch) 187 | 188 | // read up to b.N frames in background 189 | readDone := make(chan struct{}) 190 | go func() { 191 | <-outch 192 | b.StartTimer() 193 | for i := 1; i < b.N; i++ { 194 | <-outch 195 | } // NB: read never fails 196 | close(readDone) 197 | }() 198 | 199 | // connect to tcp socket and start the output loop 200 | out, err := NewFrameStreamSockOutput(l.Addr()) 201 | if err != nil { 202 | b.Fatal(err) 203 | } 204 | go out.RunOutputLoop() 205 | 206 | // write to the output channel exactly b.N frames 207 | for i := 0; i < b.N; i++ { 208 | out.GetOutputChannel() <- []byte("frame") 209 | } 210 | out.Close() 211 | 212 | // wait for the reader 213 | <-readDone 214 | } 215 | -------------------------------------------------------------------------------- /SocketWriter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dnstap 18 | 19 | import ( 20 | "net" 21 | "sync" 22 | "time" 23 | 24 | framestream "github.com/farsightsec/golang-framestream" 25 | ) 26 | 27 | // A SocketWriter writes data to a Frame Streams TCP or Unix domain socket, 28 | // establishing or restarting the connection if needed. 29 | type socketWriter struct { 30 | w Writer 31 | c net.Conn 32 | addr net.Addr 33 | opt SocketWriterOptions 34 | } 35 | 36 | // SocketWriterOptions provides configuration options for a SocketWriter 37 | type SocketWriterOptions struct { 38 | // Timeout gives the time the SocketWriter will wait for reads and 39 | // writes to complete. 40 | Timeout time.Duration 41 | // FlushTimeout is the maximum duration data will be buffered while 42 | // being written to the socket. 43 | FlushTimeout time.Duration 44 | // RetryInterval is how long the SocketWriter will wait between 45 | // connection attempts. 46 | RetryInterval time.Duration 47 | // Dialer is the dialer used to establish the connection. If nil, 48 | // SocketWriter will use a default dialer with a 30 second timeout. 49 | Dialer *net.Dialer 50 | // Logger provides the logger for connection establishment, reconnection, 51 | // and error events of the SocketWriter. 52 | Logger Logger 53 | } 54 | 55 | type flushWriter struct { 56 | m sync.Mutex 57 | w *framestream.Writer 58 | d time.Duration 59 | timer *time.Timer 60 | timerActive bool 61 | lastFlushed time.Time 62 | stopped bool 63 | } 64 | 65 | type flusherConn struct { 66 | net.Conn 67 | lastWritten *time.Time 68 | } 69 | 70 | func (c *flusherConn) Write(p []byte) (int, error) { 71 | n, err := c.Conn.Write(p) 72 | *c.lastWritten = time.Now() 73 | return n, err 74 | } 75 | 76 | func newFlushWriter(c net.Conn, d time.Duration) (*flushWriter, error) { 77 | var err error 78 | fw := &flushWriter{timer: time.NewTimer(d), d: d} 79 | if !fw.timer.Stop() { 80 | <-fw.timer.C 81 | } 82 | 83 | fc := &flusherConn{ 84 | Conn: c, 85 | lastWritten: &fw.lastFlushed, 86 | } 87 | 88 | fw.w, err = framestream.NewWriter(fc, 89 | &framestream.WriterOptions{ 90 | ContentTypes: [][]byte{FSContentType}, 91 | Bidirectional: true, 92 | Timeout: d, 93 | }) 94 | if err != nil { 95 | return nil, err 96 | } 97 | go fw.runFlusher() 98 | return fw, nil 99 | } 100 | 101 | func (fw *flushWriter) runFlusher() { 102 | for range fw.timer.C { 103 | fw.m.Lock() 104 | if fw.stopped { 105 | fw.m.Unlock() 106 | return 107 | } 108 | last := fw.lastFlushed 109 | elapsed := time.Since(last) 110 | if elapsed < fw.d { 111 | fw.timer.Reset(fw.d - elapsed) 112 | fw.m.Unlock() 113 | continue 114 | } 115 | fw.w.Flush() 116 | fw.timerActive = false 117 | fw.m.Unlock() 118 | } 119 | } 120 | 121 | func (fw *flushWriter) WriteFrame(p []byte) (int, error) { 122 | fw.m.Lock() 123 | n, err := fw.w.WriteFrame(p) 124 | if !fw.timerActive { 125 | fw.timer.Reset(fw.d) 126 | fw.timerActive = true 127 | } 128 | fw.m.Unlock() 129 | return n, err 130 | } 131 | 132 | func (fw *flushWriter) Close() error { 133 | fw.m.Lock() 134 | fw.stopped = true 135 | fw.timer.Reset(0) 136 | err := fw.w.Close() 137 | fw.m.Unlock() 138 | return err 139 | } 140 | 141 | // NewSocketWriter creates a SocketWriter which writes data to a connection 142 | // to the given addr. The SocketWriter maintains and re-establishes the 143 | // connection to this address as needed. 144 | func NewSocketWriter(addr net.Addr, opt *SocketWriterOptions) Writer { 145 | if opt == nil { 146 | opt = &SocketWriterOptions{} 147 | } 148 | 149 | if opt.Logger == nil { 150 | opt.Logger = &nullLogger{} 151 | } 152 | return &socketWriter{addr: addr, opt: *opt} 153 | } 154 | 155 | func (sw *socketWriter) openWriter() error { 156 | var err error 157 | sw.c, err = sw.opt.Dialer.Dial(sw.addr.Network(), sw.addr.String()) 158 | if err != nil { 159 | return err 160 | } 161 | 162 | wopt := WriterOptions{ 163 | Bidirectional: true, 164 | Timeout: sw.opt.Timeout, 165 | } 166 | 167 | if sw.opt.FlushTimeout == 0 { 168 | sw.w, err = NewWriter(sw.c, &wopt) 169 | } else { 170 | sw.w, err = newFlushWriter(sw.c, sw.opt.FlushTimeout) 171 | } 172 | if err != nil { 173 | sw.c.Close() 174 | return err 175 | } 176 | return nil 177 | } 178 | 179 | // Close shuts down the SocketWriter, closing any open connection. 180 | func (sw *socketWriter) Close() error { 181 | var err error 182 | if sw.w != nil { 183 | err = sw.w.Close() 184 | if err == nil { 185 | return sw.c.Close() 186 | } 187 | sw.c.Close() 188 | return err 189 | } 190 | if sw.c != nil { 191 | return sw.c.Close() 192 | } 193 | return nil 194 | } 195 | 196 | // Write writes the data in p as a Dnstap frame to a connection to the 197 | // SocketWriter's address. Write may block indefinitely while the SocketWriter 198 | // attempts to establish or re-establish the connection and FrameStream session. 199 | func (sw *socketWriter) WriteFrame(p []byte) (int, error) { 200 | for ; ; time.Sleep(sw.opt.RetryInterval) { 201 | if sw.w == nil { 202 | if err := sw.openWriter(); err != nil { 203 | sw.opt.Logger.Printf("%s: open failed: %v", sw.addr, err) 204 | continue 205 | } 206 | } 207 | 208 | n, err := sw.w.WriteFrame(p) 209 | if err != nil { 210 | sw.opt.Logger.Printf("%s: write failed: %v", sw.addr, err) 211 | sw.Close() 212 | continue 213 | } 214 | 215 | return n, nil 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /dnstap/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2019 by Farsight Security, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "log" 23 | "net" 24 | "os" 25 | "runtime" 26 | "strings" 27 | "sync" 28 | 29 | "github.com/dnstap/golang-dnstap" 30 | ) 31 | 32 | type stringList []string 33 | 34 | func (sl *stringList) Set(s string) error { 35 | *sl = append(*sl, s) 36 | return nil 37 | } 38 | func (sl *stringList) String() string { 39 | return strings.Join(*sl, ", ") 40 | } 41 | 42 | var ( 43 | flagTimeout = flag.Duration("t", 0, "I/O timeout for tcp/ip and unix domain sockets") 44 | flagWriteFile = flag.String("w", "", "write output to file") 45 | flagAppendFile = flag.Bool("a", false, "append to the given file, do not overwrite. valid only when outputting a text or YAML file.") 46 | flagQuietText = flag.Bool("q", false, "use quiet text output") 47 | flagYamlText = flag.Bool("y", false, "use verbose YAML output") 48 | flagJSONText = flag.Bool("j", false, "use verbose JSON output") 49 | ) 50 | 51 | func usage() { 52 | fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0]) 53 | flag.PrintDefaults() 54 | fmt.Fprintf(os.Stderr, ` 55 | Quiet text output format mnemonics: 56 | AQ: AUTH_QUERY 57 | AR: AUTH_RESPONSE 58 | RQ: RESOLVER_QUERY 59 | RR: RESOLVER_RESPONSE 60 | CQ: CLIENT_QUERY 61 | CR: CLIENT_RESPONSE 62 | FQ: FORWARDER_QUERY 63 | FR: FORWARDER_RESPONSE 64 | SQ: STUB_QUERY 65 | SR: STUB_RESPONSE 66 | TQ: TOOL_QUERY 67 | TR: TOOL_RESPONSE 68 | `) 69 | } 70 | 71 | var logger = log.New(os.Stderr, "", log.LstdFlags) 72 | 73 | func main() { 74 | var tcpOutputs, unixOutputs stringList 75 | var fileInputs, tcpInputs, unixInputs stringList 76 | 77 | flag.Var(&tcpOutputs, "T", "write dnstap payloads to tcp/ip address") 78 | flag.Var(&unixOutputs, "U", "write dnstap payloads to unix socket") 79 | flag.Var(&fileInputs, "r", "read dnstap payloads from file") 80 | flag.Var(&tcpInputs, "l", "read dnstap payloads from tcp/ip") 81 | flag.Var(&unixInputs, "u", "read dnstap payloads from unix socket") 82 | 83 | runtime.GOMAXPROCS(runtime.NumCPU()) 84 | log.SetFlags(0) 85 | flag.Usage = usage 86 | 87 | // Handle command-line arguments. 88 | flag.Parse() 89 | 90 | if len(fileInputs)+len(unixInputs)+len(tcpInputs) == 0 { 91 | fmt.Fprintf(os.Stderr, "dnstap: Error: no inputs specified.\n") 92 | os.Exit(1) 93 | } 94 | 95 | haveFormat := false 96 | for _, f := range []bool{*flagQuietText, *flagYamlText, *flagJSONText} { 97 | if haveFormat && f { 98 | fmt.Fprintf(os.Stderr, "dnstap: Error: specify at most one of -q, -y, or -j.\n") 99 | os.Exit(1) 100 | } 101 | haveFormat = haveFormat || f 102 | } 103 | 104 | output := newMirrorOutput() 105 | if err := addSockOutputs(output, "tcp", tcpOutputs); err != nil { 106 | fmt.Fprintf(os.Stderr, "dnstap: TCP error: %v\n", err) 107 | os.Exit(1) 108 | } 109 | if err := addSockOutputs(output, "unix", unixOutputs); err != nil { 110 | fmt.Fprintf(os.Stderr, "dnstap: Unix socket error: %v\n", err) 111 | os.Exit(1) 112 | } 113 | if *flagWriteFile != "" || len(tcpOutputs)+len(unixOutputs) == 0 { 114 | var format dnstap.TextFormatFunc 115 | 116 | switch { 117 | case *flagYamlText: 118 | format = dnstap.YamlFormat 119 | case *flagQuietText: 120 | format = dnstap.TextFormat 121 | case *flagJSONText: 122 | format = dnstap.JSONFormat 123 | } 124 | 125 | o, err := newFileOutput(*flagWriteFile, format, *flagAppendFile) 126 | if err != nil { 127 | fmt.Fprintf(os.Stderr, "dnstap: File output error on '%s': %v\n", 128 | *flagWriteFile, err) 129 | os.Exit(1) 130 | } 131 | go o.RunOutputLoop() 132 | output.Add(o) 133 | } 134 | 135 | go output.RunOutputLoop() 136 | 137 | var iwg sync.WaitGroup 138 | // Open the input and start the input loop. 139 | for _, fname := range fileInputs { 140 | i, err := dnstap.NewFrameStreamInputFromFilename(fname) 141 | if err != nil { 142 | fmt.Fprintf(os.Stderr, "dnstap: Failed to open input file %s: %v\n", fname, err) 143 | os.Exit(1) 144 | } 145 | i.SetLogger(logger) 146 | fmt.Fprintf(os.Stderr, "dnstap: opened input file %s\n", fname) 147 | iwg.Add(1) 148 | go runInput(i, output, &iwg) 149 | } 150 | for _, path := range unixInputs { 151 | i, err := dnstap.NewFrameStreamSockInputFromPath(path) 152 | if err != nil { 153 | fmt.Fprintf(os.Stderr, "dnstap: Failed to open input socket %s: %v\n", path, err) 154 | os.Exit(1) 155 | } 156 | i.SetTimeout(*flagTimeout) 157 | i.SetLogger(logger) 158 | fmt.Fprintf(os.Stderr, "dnstap: opened input socket %s\n", path) 159 | iwg.Add(1) 160 | go runInput(i, output, &iwg) 161 | } 162 | for _, addr := range tcpInputs { 163 | l, err := net.Listen("tcp", addr) 164 | if err != nil { 165 | fmt.Fprintf(os.Stderr, "dnstap: Failed to listen on %s: %v\n", addr, err) 166 | os.Exit(1) 167 | } 168 | i := dnstap.NewFrameStreamSockInput(l) 169 | i.SetTimeout(*flagTimeout) 170 | i.SetLogger(logger) 171 | iwg.Add(1) 172 | go runInput(i, output, &iwg) 173 | } 174 | iwg.Wait() 175 | 176 | output.Close() 177 | } 178 | 179 | func runInput(i dnstap.Input, o dnstap.Output, wg *sync.WaitGroup) { 180 | go i.ReadInto(o.GetOutputChannel()) 181 | i.Wait() 182 | wg.Done() 183 | } 184 | 185 | func addSockOutputs(mo *mirrorOutput, network string, addrs stringList) error { 186 | var naddr net.Addr 187 | var err error 188 | for _, addr := range addrs { 189 | switch network { 190 | case "tcp": 191 | naddr, err = net.ResolveTCPAddr(network, addr) 192 | case "unix": 193 | naddr, err = net.ResolveUnixAddr(network, addr) 194 | default: 195 | return fmt.Errorf("invalid network '%s'", network) 196 | } 197 | if err != nil { 198 | return err 199 | } 200 | 201 | o, err := dnstap.NewFrameStreamSockOutput(naddr) 202 | if err != nil { 203 | return err 204 | } 205 | o.SetTimeout(*flagTimeout) 206 | o.SetLogger(logger) 207 | go o.RunOutputLoop() 208 | mo.Add(o) 209 | } 210 | return nil 211 | } 212 | -------------------------------------------------------------------------------- /dnstap.pb/LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /dnstap.pb/dnstap.proto: -------------------------------------------------------------------------------- 1 | // dnstap: flexible, structured event replication format for DNS software 2 | // 3 | // This file contains the protobuf schemas for the "dnstap" structured event 4 | // replication format for DNS software. 5 | 6 | // Written in 2013-2014 by Farsight Security, Inc. 7 | // 8 | // To the extent possible under law, the author(s) have dedicated all 9 | // copyright and related and neighboring rights to this file to the public 10 | // domain worldwide. This file is distributed without any warranty. 11 | // 12 | // You should have received a copy of the CC0 Public Domain Dedication along 13 | // with this file. If not, see: 14 | // 15 | // . 16 | 17 | syntax = "proto2"; 18 | package dnstap; 19 | option go_package = "github.com/dnstap/golang-dnstap;dnstap"; 20 | 21 | // "Dnstap": this is the top-level dnstap type, which is a "union" type that 22 | // contains other kinds of dnstap payloads, although currently only one type 23 | // of dnstap payload is defined. 24 | // See: https://developers.google.com/protocol-buffers/docs/techniques#union 25 | message Dnstap { 26 | // DNS server identity. 27 | // If enabled, this is the identity string of the DNS server which generated 28 | // this message. Typically this would be the same string as returned by an 29 | // "NSID" (RFC 5001) query. 30 | optional bytes identity = 1; 31 | 32 | // DNS server version. 33 | // If enabled, this is the version string of the DNS server which generated 34 | // this message. Typically this would be the same string as returned by a 35 | // "version.bind" query. 36 | optional bytes version = 2; 37 | 38 | // Extra data for this payload. 39 | // This field can be used for adding an arbitrary byte-string annotation to 40 | // the payload. No encoding or interpretation is applied or enforced. 41 | optional bytes extra = 3; 42 | 43 | // Identifies which field below is filled in. 44 | enum Type { 45 | MESSAGE = 1; 46 | } 47 | required Type type = 15; 48 | 49 | // One of the following will be filled in. 50 | optional Message message = 14; 51 | } 52 | 53 | // SocketFamily: the network protocol family of a socket. This specifies how 54 | // to interpret "network address" fields. 55 | enum SocketFamily { 56 | INET = 1; // IPv4 (RFC 791) 57 | INET6 = 2; // IPv6 (RFC 2460) 58 | } 59 | 60 | // SocketProtocol: the protocol used to transport a DNS message. 61 | enum SocketProtocol { 62 | UDP = 1; // DNS over UDP transport (RFC 1035 section 4.2.1) 63 | TCP = 2; // DNS over TCP transport (RFC 1035 section 4.2.2) 64 | DOT = 3; // DNS over TLS (RFC 7858) 65 | DOH = 4; // DNS over HTTPS (RFC 8484) 66 | } 67 | 68 | // Message: a wire-format (RFC 1035 section 4) DNS message and associated 69 | // metadata. Applications generating "Message" payloads should follow 70 | // certain requirements based on the MessageType, see below. 71 | message Message { 72 | 73 | // There are eight types of "Message" defined that correspond to the 74 | // four arrows in the following diagram, slightly modified from RFC 1035 75 | // section 2: 76 | 77 | // +---------+ +----------+ +--------+ 78 | // | | query | | query | | 79 | // | Stub |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth. | 80 | // | Resolver| | Server | | Name | 81 | // | |<-SR--------CR-| |<-RR----AR-| Server | 82 | // +---------+ response | | response | | 83 | // +----------+ +--------+ 84 | 85 | // Each arrow has two Type values each, one for each "end" of each arrow, 86 | // because these are considered to be distinct events. Each end of each 87 | // arrow on the diagram above has been marked with a two-letter Type 88 | // mnemonic. Clockwise from upper left, these mnemonic values are: 89 | // 90 | // SQ: STUB_QUERY 91 | // CQ: CLIENT_QUERY 92 | // RQ: RESOLVER_QUERY 93 | // AQ: AUTH_QUERY 94 | // AR: AUTH_RESPONSE 95 | // RR: RESOLVER_RESPONSE 96 | // CR: CLIENT_RESPONSE 97 | // SR: STUB_RESPONSE 98 | 99 | // Two additional types of "Message" have been defined for the 100 | // "forwarding" case where an upstream DNS server is responsible for 101 | // further recursion. These are not shown on the diagram above, but have 102 | // the following mnemonic values: 103 | 104 | // FQ: FORWARDER_QUERY 105 | // FR: FORWARDER_RESPONSE 106 | 107 | // The "Message" Type values are defined below. 108 | 109 | enum Type { 110 | // AUTH_QUERY is a DNS query message received from a resolver by an 111 | // authoritative name server, from the perspective of the authoritative 112 | // name server. 113 | AUTH_QUERY = 1; 114 | 115 | // AUTH_RESPONSE is a DNS response message sent from an authoritative 116 | // name server to a resolver, from the perspective of the authoritative 117 | // name server. 118 | AUTH_RESPONSE = 2; 119 | 120 | // RESOLVER_QUERY is a DNS query message sent from a resolver to an 121 | // authoritative name server, from the perspective of the resolver. 122 | // Resolvers typically clear the RD (recursion desired) bit when 123 | // sending queries. 124 | RESOLVER_QUERY = 3; 125 | 126 | // RESOLVER_RESPONSE is a DNS response message received from an 127 | // authoritative name server by a resolver, from the perspective of 128 | // the resolver. 129 | RESOLVER_RESPONSE = 4; 130 | 131 | // CLIENT_QUERY is a DNS query message sent from a client to a DNS 132 | // server which is expected to perform further recursion, from the 133 | // perspective of the DNS server. The client may be a stub resolver or 134 | // forwarder or some other type of software which typically sets the RD 135 | // (recursion desired) bit when querying the DNS server. The DNS server 136 | // may be a simple forwarding proxy or it may be a full recursive 137 | // resolver. 138 | CLIENT_QUERY = 5; 139 | 140 | // CLIENT_RESPONSE is a DNS response message sent from a DNS server to 141 | // a client, from the perspective of the DNS server. The DNS server 142 | // typically sets the RA (recursion available) bit when responding. 143 | CLIENT_RESPONSE = 6; 144 | 145 | // FORWARDER_QUERY is a DNS query message sent from a downstream DNS 146 | // server to an upstream DNS server which is expected to perform 147 | // further recursion, from the perspective of the downstream DNS 148 | // server. 149 | FORWARDER_QUERY = 7; 150 | 151 | // FORWARDER_RESPONSE is a DNS response message sent from an upstream 152 | // DNS server performing recursion to a downstream DNS server, from the 153 | // perspective of the downstream DNS server. 154 | FORWARDER_RESPONSE = 8; 155 | 156 | // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS 157 | // server, from the perspective of the stub resolver. 158 | STUB_QUERY = 9; 159 | 160 | // STUB_RESPONSE is a DNS response message sent from a DNS server to a 161 | // stub resolver, from the perspective of the stub resolver. 162 | STUB_RESPONSE = 10; 163 | 164 | // TOOL_QUERY is a DNS query message sent from a DNS software tool to a 165 | // DNS server, from the perspective of the tool. 166 | TOOL_QUERY = 11; 167 | 168 | // TOOL_RESPONSE is a DNS response message received by a DNS software 169 | // tool from a DNS server, from the perspective of the tool. 170 | TOOL_RESPONSE = 12; 171 | 172 | // UPDATE_QUERY is a DNS update query message received from a resolver 173 | // by an authoritative name server, from the perspective of the 174 | // authoritative name server. 175 | UPDATE_QUERY = 13; 176 | 177 | // UPDATE_RESPONSE is a DNS update response message sent from an 178 | // authoritative name server to a resolver, from the perspective of the 179 | // authoritative name server. 180 | UPDATE_RESPONSE = 14; 181 | } 182 | 183 | // One of the Type values described above. 184 | required Type type = 1; 185 | 186 | // One of the SocketFamily values described above. 187 | optional SocketFamily socket_family = 2; 188 | 189 | // One of the SocketProtocol values described above. 190 | optional SocketProtocol socket_protocol = 3; 191 | 192 | // The network address of the message initiator. 193 | // For SocketFamily INET, this field is 4 octets (IPv4 address). 194 | // For SocketFamily INET6, this field is 16 octets (IPv6 address). 195 | optional bytes query_address = 4; 196 | 197 | // The network address of the message responder. 198 | // For SocketFamily INET, this field is 4 octets (IPv4 address). 199 | // For SocketFamily INET6, this field is 16 octets (IPv6 address). 200 | optional bytes response_address = 5; 201 | 202 | // The transport port of the message initiator. 203 | // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. 204 | optional uint32 query_port = 6; 205 | 206 | // The transport port of the message responder. 207 | // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. 208 | optional uint32 response_port = 7; 209 | 210 | // The time at which the DNS query message was sent or received, depending 211 | // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. 212 | // This is the number of seconds since the UNIX epoch. 213 | optional uint64 query_time_sec = 8; 214 | 215 | // The time at which the DNS query message was sent or received. 216 | // This is the seconds fraction, expressed as a count of nanoseconds. 217 | optional fixed32 query_time_nsec = 9; 218 | 219 | // The initiator's original wire-format DNS query message, verbatim. 220 | optional bytes query_message = 10; 221 | 222 | // The "zone" or "bailiwick" pertaining to the DNS query message. 223 | // This is a wire-format DNS domain name. 224 | optional bytes query_zone = 11; 225 | 226 | // The time at which the DNS response message was sent or received, 227 | // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or 228 | // CLIENT_RESPONSE. 229 | // This is the number of seconds since the UNIX epoch. 230 | optional uint64 response_time_sec = 12; 231 | 232 | // The time at which the DNS response message was sent or received. 233 | // This is the seconds fraction, expressed as a count of nanoseconds. 234 | optional fixed32 response_time_nsec = 13; 235 | 236 | // The responder's original wire-format DNS response message, verbatim. 237 | optional bytes response_message = 14; 238 | } 239 | 240 | // All fields except for 'type' in the Message schema are optional. 241 | // It is recommended that at least the following fields be filled in for 242 | // particular types of Messages. 243 | 244 | // AUTH_QUERY: 245 | // socket_family, socket_protocol 246 | // query_address, query_port 247 | // query_message 248 | // query_time_sec, query_time_nsec 249 | 250 | // AUTH_RESPONSE: 251 | // socket_family, socket_protocol 252 | // query_address, query_port 253 | // query_time_sec, query_time_nsec 254 | // response_message 255 | // response_time_sec, response_time_nsec 256 | 257 | // RESOLVER_QUERY: 258 | // socket_family, socket_protocol 259 | // query_message 260 | // query_time_sec, query_time_nsec 261 | // query_zone 262 | // response_address, response_port 263 | 264 | // RESOLVER_RESPONSE: 265 | // socket_family, socket_protocol 266 | // query_time_sec, query_time_nsec 267 | // query_zone 268 | // response_address, response_port 269 | // response_message 270 | // response_time_sec, response_time_nsec 271 | 272 | // CLIENT_QUERY: 273 | // socket_family, socket_protocol 274 | // query_message 275 | // query_time_sec, query_time_nsec 276 | 277 | // CLIENT_RESPONSE: 278 | // socket_family, socket_protocol 279 | // query_time_sec, query_time_nsec 280 | // response_message 281 | // response_time_sec, response_time_nsec 282 | -------------------------------------------------------------------------------- /dnstap.pb.go: -------------------------------------------------------------------------------- 1 | // dnstap: flexible, structured event replication format for DNS software 2 | // 3 | // This file contains the protobuf schemas for the "dnstap" structured event 4 | // replication format for DNS software. 5 | 6 | // Written in 2013-2014 by Farsight Security, Inc. 7 | // 8 | // To the extent possible under law, the author(s) have dedicated all 9 | // copyright and related and neighboring rights to this file to the public 10 | // domain worldwide. This file is distributed without any warranty. 11 | // 12 | // You should have received a copy of the CC0 Public Domain Dedication along 13 | // with this file. If not, see: 14 | // 15 | // . 16 | 17 | // Code generated by protoc-gen-go. DO NOT EDIT. 18 | // versions: 19 | // protoc-gen-go v1.25.0-devel 20 | // protoc (unknown) 21 | // source: dnstap.proto 22 | 23 | package dnstap 24 | 25 | import ( 26 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 27 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 28 | reflect "reflect" 29 | sync "sync" 30 | ) 31 | 32 | const ( 33 | // Verify that this generated code is sufficiently up-to-date. 34 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 35 | // Verify that runtime/protoimpl is sufficiently up-to-date. 36 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 37 | ) 38 | 39 | // SocketFamily: the network protocol family of a socket. This specifies how 40 | // to interpret "network address" fields. 41 | type SocketFamily int32 42 | 43 | const ( 44 | SocketFamily_INET SocketFamily = 1 // IPv4 (RFC 791) 45 | SocketFamily_INET6 SocketFamily = 2 // IPv6 (RFC 2460) 46 | ) 47 | 48 | // Enum value maps for SocketFamily. 49 | var ( 50 | SocketFamily_name = map[int32]string{ 51 | 1: "INET", 52 | 2: "INET6", 53 | } 54 | SocketFamily_value = map[string]int32{ 55 | "INET": 1, 56 | "INET6": 2, 57 | } 58 | ) 59 | 60 | func (x SocketFamily) Enum() *SocketFamily { 61 | p := new(SocketFamily) 62 | *p = x 63 | return p 64 | } 65 | 66 | func (x SocketFamily) String() string { 67 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 68 | } 69 | 70 | func (SocketFamily) Descriptor() protoreflect.EnumDescriptor { 71 | return file_dnstap_proto_enumTypes[0].Descriptor() 72 | } 73 | 74 | func (SocketFamily) Type() protoreflect.EnumType { 75 | return &file_dnstap_proto_enumTypes[0] 76 | } 77 | 78 | func (x SocketFamily) Number() protoreflect.EnumNumber { 79 | return protoreflect.EnumNumber(x) 80 | } 81 | 82 | // Deprecated: Do not use. 83 | func (x *SocketFamily) UnmarshalJSON(b []byte) error { 84 | num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) 85 | if err != nil { 86 | return err 87 | } 88 | *x = SocketFamily(num) 89 | return nil 90 | } 91 | 92 | // Deprecated: Use SocketFamily.Descriptor instead. 93 | func (SocketFamily) EnumDescriptor() ([]byte, []int) { 94 | return file_dnstap_proto_rawDescGZIP(), []int{0} 95 | } 96 | 97 | // SocketProtocol: the protocol used to transport a DNS message. 98 | type SocketProtocol int32 99 | 100 | const ( 101 | SocketProtocol_UDP SocketProtocol = 1 // DNS over UDP transport (RFC 1035 section 4.2.1) 102 | SocketProtocol_TCP SocketProtocol = 2 // DNS over TCP transport (RFC 1035 section 4.2.2) 103 | SocketProtocol_DOT SocketProtocol = 3 // DNS over TLS (RFC 7858) 104 | SocketProtocol_DOH SocketProtocol = 4 // DNS over HTTPS (RFC 8484) 105 | ) 106 | 107 | // Enum value maps for SocketProtocol. 108 | var ( 109 | SocketProtocol_name = map[int32]string{ 110 | 1: "UDP", 111 | 2: "TCP", 112 | 3: "DOT", 113 | 4: "DOH", 114 | } 115 | SocketProtocol_value = map[string]int32{ 116 | "UDP": 1, 117 | "TCP": 2, 118 | "DOT": 3, 119 | "DOH": 4, 120 | } 121 | ) 122 | 123 | func (x SocketProtocol) Enum() *SocketProtocol { 124 | p := new(SocketProtocol) 125 | *p = x 126 | return p 127 | } 128 | 129 | func (x SocketProtocol) String() string { 130 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 131 | } 132 | 133 | func (SocketProtocol) Descriptor() protoreflect.EnumDescriptor { 134 | return file_dnstap_proto_enumTypes[1].Descriptor() 135 | } 136 | 137 | func (SocketProtocol) Type() protoreflect.EnumType { 138 | return &file_dnstap_proto_enumTypes[1] 139 | } 140 | 141 | func (x SocketProtocol) Number() protoreflect.EnumNumber { 142 | return protoreflect.EnumNumber(x) 143 | } 144 | 145 | // Deprecated: Do not use. 146 | func (x *SocketProtocol) UnmarshalJSON(b []byte) error { 147 | num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) 148 | if err != nil { 149 | return err 150 | } 151 | *x = SocketProtocol(num) 152 | return nil 153 | } 154 | 155 | // Deprecated: Use SocketProtocol.Descriptor instead. 156 | func (SocketProtocol) EnumDescriptor() ([]byte, []int) { 157 | return file_dnstap_proto_rawDescGZIP(), []int{1} 158 | } 159 | 160 | // Identifies which field below is filled in. 161 | type Dnstap_Type int32 162 | 163 | const ( 164 | Dnstap_MESSAGE Dnstap_Type = 1 165 | ) 166 | 167 | // Enum value maps for Dnstap_Type. 168 | var ( 169 | Dnstap_Type_name = map[int32]string{ 170 | 1: "MESSAGE", 171 | } 172 | Dnstap_Type_value = map[string]int32{ 173 | "MESSAGE": 1, 174 | } 175 | ) 176 | 177 | func (x Dnstap_Type) Enum() *Dnstap_Type { 178 | p := new(Dnstap_Type) 179 | *p = x 180 | return p 181 | } 182 | 183 | func (x Dnstap_Type) String() string { 184 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 185 | } 186 | 187 | func (Dnstap_Type) Descriptor() protoreflect.EnumDescriptor { 188 | return file_dnstap_proto_enumTypes[2].Descriptor() 189 | } 190 | 191 | func (Dnstap_Type) Type() protoreflect.EnumType { 192 | return &file_dnstap_proto_enumTypes[2] 193 | } 194 | 195 | func (x Dnstap_Type) Number() protoreflect.EnumNumber { 196 | return protoreflect.EnumNumber(x) 197 | } 198 | 199 | // Deprecated: Do not use. 200 | func (x *Dnstap_Type) UnmarshalJSON(b []byte) error { 201 | num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) 202 | if err != nil { 203 | return err 204 | } 205 | *x = Dnstap_Type(num) 206 | return nil 207 | } 208 | 209 | // Deprecated: Use Dnstap_Type.Descriptor instead. 210 | func (Dnstap_Type) EnumDescriptor() ([]byte, []int) { 211 | return file_dnstap_proto_rawDescGZIP(), []int{0, 0} 212 | } 213 | 214 | type Message_Type int32 215 | 216 | const ( 217 | // AUTH_QUERY is a DNS query message received from a resolver by an 218 | // authoritative name server, from the perspective of the authoritative 219 | // name server. 220 | Message_AUTH_QUERY Message_Type = 1 221 | // AUTH_RESPONSE is a DNS response message sent from an authoritative 222 | // name server to a resolver, from the perspective of the authoritative 223 | // name server. 224 | Message_AUTH_RESPONSE Message_Type = 2 225 | // RESOLVER_QUERY is a DNS query message sent from a resolver to an 226 | // authoritative name server, from the perspective of the resolver. 227 | // Resolvers typically clear the RD (recursion desired) bit when 228 | // sending queries. 229 | Message_RESOLVER_QUERY Message_Type = 3 230 | // RESOLVER_RESPONSE is a DNS response message received from an 231 | // authoritative name server by a resolver, from the perspective of 232 | // the resolver. 233 | Message_RESOLVER_RESPONSE Message_Type = 4 234 | // CLIENT_QUERY is a DNS query message sent from a client to a DNS 235 | // server which is expected to perform further recursion, from the 236 | // perspective of the DNS server. The client may be a stub resolver or 237 | // forwarder or some other type of software which typically sets the RD 238 | // (recursion desired) bit when querying the DNS server. The DNS server 239 | // may be a simple forwarding proxy or it may be a full recursive 240 | // resolver. 241 | Message_CLIENT_QUERY Message_Type = 5 242 | // CLIENT_RESPONSE is a DNS response message sent from a DNS server to 243 | // a client, from the perspective of the DNS server. The DNS server 244 | // typically sets the RA (recursion available) bit when responding. 245 | Message_CLIENT_RESPONSE Message_Type = 6 246 | // FORWARDER_QUERY is a DNS query message sent from a downstream DNS 247 | // server to an upstream DNS server which is expected to perform 248 | // further recursion, from the perspective of the downstream DNS 249 | // server. 250 | Message_FORWARDER_QUERY Message_Type = 7 251 | // FORWARDER_RESPONSE is a DNS response message sent from an upstream 252 | // DNS server performing recursion to a downstream DNS server, from the 253 | // perspective of the downstream DNS server. 254 | Message_FORWARDER_RESPONSE Message_Type = 8 255 | // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS 256 | // server, from the perspective of the stub resolver. 257 | Message_STUB_QUERY Message_Type = 9 258 | // STUB_RESPONSE is a DNS response message sent from a DNS server to a 259 | // stub resolver, from the perspective of the stub resolver. 260 | Message_STUB_RESPONSE Message_Type = 10 261 | // TOOL_QUERY is a DNS query message sent from a DNS software tool to a 262 | // DNS server, from the perspective of the tool. 263 | Message_TOOL_QUERY Message_Type = 11 264 | // TOOL_RESPONSE is a DNS response message received by a DNS software 265 | // tool from a DNS server, from the perspective of the tool. 266 | Message_TOOL_RESPONSE Message_Type = 12 267 | // UPDATE_QUERY is a DNS update query message received from a resolver 268 | // by an authoritative name server, from the perspective of the 269 | // authoritative name server. 270 | Message_UPDATE_QUERY Message_Type = 13 271 | // UPDATE_RESPONSE is a DNS update response message sent from an 272 | // authoritative name server to a resolver, from the perspective of the 273 | // authoritative name server. 274 | Message_UPDATE_RESPONSE Message_Type = 14 275 | ) 276 | 277 | // Enum value maps for Message_Type. 278 | var ( 279 | Message_Type_name = map[int32]string{ 280 | 1: "AUTH_QUERY", 281 | 2: "AUTH_RESPONSE", 282 | 3: "RESOLVER_QUERY", 283 | 4: "RESOLVER_RESPONSE", 284 | 5: "CLIENT_QUERY", 285 | 6: "CLIENT_RESPONSE", 286 | 7: "FORWARDER_QUERY", 287 | 8: "FORWARDER_RESPONSE", 288 | 9: "STUB_QUERY", 289 | 10: "STUB_RESPONSE", 290 | 11: "TOOL_QUERY", 291 | 12: "TOOL_RESPONSE", 292 | 13: "UPDATE_QUERY", 293 | 14: "UPDATE_RESPONSE", 294 | } 295 | Message_Type_value = map[string]int32{ 296 | "AUTH_QUERY": 1, 297 | "AUTH_RESPONSE": 2, 298 | "RESOLVER_QUERY": 3, 299 | "RESOLVER_RESPONSE": 4, 300 | "CLIENT_QUERY": 5, 301 | "CLIENT_RESPONSE": 6, 302 | "FORWARDER_QUERY": 7, 303 | "FORWARDER_RESPONSE": 8, 304 | "STUB_QUERY": 9, 305 | "STUB_RESPONSE": 10, 306 | "TOOL_QUERY": 11, 307 | "TOOL_RESPONSE": 12, 308 | "UPDATE_QUERY": 13, 309 | "UPDATE_RESPONSE": 14, 310 | } 311 | ) 312 | 313 | func (x Message_Type) Enum() *Message_Type { 314 | p := new(Message_Type) 315 | *p = x 316 | return p 317 | } 318 | 319 | func (x Message_Type) String() string { 320 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 321 | } 322 | 323 | func (Message_Type) Descriptor() protoreflect.EnumDescriptor { 324 | return file_dnstap_proto_enumTypes[3].Descriptor() 325 | } 326 | 327 | func (Message_Type) Type() protoreflect.EnumType { 328 | return &file_dnstap_proto_enumTypes[3] 329 | } 330 | 331 | func (x Message_Type) Number() protoreflect.EnumNumber { 332 | return protoreflect.EnumNumber(x) 333 | } 334 | 335 | // Deprecated: Do not use. 336 | func (x *Message_Type) UnmarshalJSON(b []byte) error { 337 | num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) 338 | if err != nil { 339 | return err 340 | } 341 | *x = Message_Type(num) 342 | return nil 343 | } 344 | 345 | // Deprecated: Use Message_Type.Descriptor instead. 346 | func (Message_Type) EnumDescriptor() ([]byte, []int) { 347 | return file_dnstap_proto_rawDescGZIP(), []int{1, 0} 348 | } 349 | 350 | // "Dnstap": this is the top-level dnstap type, which is a "union" type that 351 | // contains other kinds of dnstap payloads, although currently only one type 352 | // of dnstap payload is defined. 353 | // See: https://developers.google.com/protocol-buffers/docs/techniques#union 354 | type Dnstap struct { 355 | state protoimpl.MessageState 356 | sizeCache protoimpl.SizeCache 357 | unknownFields protoimpl.UnknownFields 358 | 359 | // DNS server identity. 360 | // If enabled, this is the identity string of the DNS server which generated 361 | // this message. Typically this would be the same string as returned by an 362 | // "NSID" (RFC 5001) query. 363 | Identity []byte `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` 364 | // DNS server version. 365 | // If enabled, this is the version string of the DNS server which generated 366 | // this message. Typically this would be the same string as returned by a 367 | // "version.bind" query. 368 | Version []byte `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` 369 | // Extra data for this payload. 370 | // This field can be used for adding an arbitrary byte-string annotation to 371 | // the payload. No encoding or interpretation is applied or enforced. 372 | Extra []byte `protobuf:"bytes,3,opt,name=extra" json:"extra,omitempty"` 373 | Type *Dnstap_Type `protobuf:"varint,15,req,name=type,enum=dnstap.Dnstap_Type" json:"type,omitempty"` 374 | // One of the following will be filled in. 375 | Message *Message `protobuf:"bytes,14,opt,name=message" json:"message,omitempty"` 376 | } 377 | 378 | func (x *Dnstap) Reset() { 379 | *x = Dnstap{} 380 | if protoimpl.UnsafeEnabled { 381 | mi := &file_dnstap_proto_msgTypes[0] 382 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 383 | ms.StoreMessageInfo(mi) 384 | } 385 | } 386 | 387 | func (x *Dnstap) String() string { 388 | return protoimpl.X.MessageStringOf(x) 389 | } 390 | 391 | func (*Dnstap) ProtoMessage() {} 392 | 393 | func (x *Dnstap) ProtoReflect() protoreflect.Message { 394 | mi := &file_dnstap_proto_msgTypes[0] 395 | if protoimpl.UnsafeEnabled && x != nil { 396 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 397 | if ms.LoadMessageInfo() == nil { 398 | ms.StoreMessageInfo(mi) 399 | } 400 | return ms 401 | } 402 | return mi.MessageOf(x) 403 | } 404 | 405 | // Deprecated: Use Dnstap.ProtoReflect.Descriptor instead. 406 | func (*Dnstap) Descriptor() ([]byte, []int) { 407 | return file_dnstap_proto_rawDescGZIP(), []int{0} 408 | } 409 | 410 | func (x *Dnstap) GetIdentity() []byte { 411 | if x != nil { 412 | return x.Identity 413 | } 414 | return nil 415 | } 416 | 417 | func (x *Dnstap) GetVersion() []byte { 418 | if x != nil { 419 | return x.Version 420 | } 421 | return nil 422 | } 423 | 424 | func (x *Dnstap) GetExtra() []byte { 425 | if x != nil { 426 | return x.Extra 427 | } 428 | return nil 429 | } 430 | 431 | func (x *Dnstap) GetType() Dnstap_Type { 432 | if x != nil && x.Type != nil { 433 | return *x.Type 434 | } 435 | return Dnstap_MESSAGE 436 | } 437 | 438 | func (x *Dnstap) GetMessage() *Message { 439 | if x != nil { 440 | return x.Message 441 | } 442 | return nil 443 | } 444 | 445 | // Message: a wire-format (RFC 1035 section 4) DNS message and associated 446 | // metadata. Applications generating "Message" payloads should follow 447 | // certain requirements based on the MessageType, see below. 448 | type Message struct { 449 | state protoimpl.MessageState 450 | sizeCache protoimpl.SizeCache 451 | unknownFields protoimpl.UnknownFields 452 | 453 | // One of the Type values described above. 454 | Type *Message_Type `protobuf:"varint,1,req,name=type,enum=dnstap.Message_Type" json:"type,omitempty"` 455 | // One of the SocketFamily values described above. 456 | SocketFamily *SocketFamily `protobuf:"varint,2,opt,name=socket_family,json=socketFamily,enum=dnstap.SocketFamily" json:"socket_family,omitempty"` 457 | // One of the SocketProtocol values described above. 458 | SocketProtocol *SocketProtocol `protobuf:"varint,3,opt,name=socket_protocol,json=socketProtocol,enum=dnstap.SocketProtocol" json:"socket_protocol,omitempty"` 459 | // The network address of the message initiator. 460 | // For SocketFamily INET, this field is 4 octets (IPv4 address). 461 | // For SocketFamily INET6, this field is 16 octets (IPv6 address). 462 | QueryAddress []byte `protobuf:"bytes,4,opt,name=query_address,json=queryAddress" json:"query_address,omitempty"` 463 | // The network address of the message responder. 464 | // For SocketFamily INET, this field is 4 octets (IPv4 address). 465 | // For SocketFamily INET6, this field is 16 octets (IPv6 address). 466 | ResponseAddress []byte `protobuf:"bytes,5,opt,name=response_address,json=responseAddress" json:"response_address,omitempty"` 467 | // The transport port of the message initiator. 468 | // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. 469 | QueryPort *uint32 `protobuf:"varint,6,opt,name=query_port,json=queryPort" json:"query_port,omitempty"` 470 | // The transport port of the message responder. 471 | // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. 472 | ResponsePort *uint32 `protobuf:"varint,7,opt,name=response_port,json=responsePort" json:"response_port,omitempty"` 473 | // The time at which the DNS query message was sent or received, depending 474 | // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. 475 | // This is the number of seconds since the UNIX epoch. 476 | QueryTimeSec *uint64 `protobuf:"varint,8,opt,name=query_time_sec,json=queryTimeSec" json:"query_time_sec,omitempty"` 477 | // The time at which the DNS query message was sent or received. 478 | // This is the seconds fraction, expressed as a count of nanoseconds. 479 | QueryTimeNsec *uint32 `protobuf:"fixed32,9,opt,name=query_time_nsec,json=queryTimeNsec" json:"query_time_nsec,omitempty"` 480 | // The initiator's original wire-format DNS query message, verbatim. 481 | QueryMessage []byte `protobuf:"bytes,10,opt,name=query_message,json=queryMessage" json:"query_message,omitempty"` 482 | // The "zone" or "bailiwick" pertaining to the DNS query message. 483 | // This is a wire-format DNS domain name. 484 | QueryZone []byte `protobuf:"bytes,11,opt,name=query_zone,json=queryZone" json:"query_zone,omitempty"` 485 | // The time at which the DNS response message was sent or received, 486 | // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or 487 | // CLIENT_RESPONSE. 488 | // This is the number of seconds since the UNIX epoch. 489 | ResponseTimeSec *uint64 `protobuf:"varint,12,opt,name=response_time_sec,json=responseTimeSec" json:"response_time_sec,omitempty"` 490 | // The time at which the DNS response message was sent or received. 491 | // This is the seconds fraction, expressed as a count of nanoseconds. 492 | ResponseTimeNsec *uint32 `protobuf:"fixed32,13,opt,name=response_time_nsec,json=responseTimeNsec" json:"response_time_nsec,omitempty"` 493 | // The responder's original wire-format DNS response message, verbatim. 494 | ResponseMessage []byte `protobuf:"bytes,14,opt,name=response_message,json=responseMessage" json:"response_message,omitempty"` 495 | } 496 | 497 | func (x *Message) Reset() { 498 | *x = Message{} 499 | if protoimpl.UnsafeEnabled { 500 | mi := &file_dnstap_proto_msgTypes[1] 501 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 502 | ms.StoreMessageInfo(mi) 503 | } 504 | } 505 | 506 | func (x *Message) String() string { 507 | return protoimpl.X.MessageStringOf(x) 508 | } 509 | 510 | func (*Message) ProtoMessage() {} 511 | 512 | func (x *Message) ProtoReflect() protoreflect.Message { 513 | mi := &file_dnstap_proto_msgTypes[1] 514 | if protoimpl.UnsafeEnabled && x != nil { 515 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 516 | if ms.LoadMessageInfo() == nil { 517 | ms.StoreMessageInfo(mi) 518 | } 519 | return ms 520 | } 521 | return mi.MessageOf(x) 522 | } 523 | 524 | // Deprecated: Use Message.ProtoReflect.Descriptor instead. 525 | func (*Message) Descriptor() ([]byte, []int) { 526 | return file_dnstap_proto_rawDescGZIP(), []int{1} 527 | } 528 | 529 | func (x *Message) GetType() Message_Type { 530 | if x != nil && x.Type != nil { 531 | return *x.Type 532 | } 533 | return Message_AUTH_QUERY 534 | } 535 | 536 | func (x *Message) GetSocketFamily() SocketFamily { 537 | if x != nil && x.SocketFamily != nil { 538 | return *x.SocketFamily 539 | } 540 | return SocketFamily_INET 541 | } 542 | 543 | func (x *Message) GetSocketProtocol() SocketProtocol { 544 | if x != nil && x.SocketProtocol != nil { 545 | return *x.SocketProtocol 546 | } 547 | return SocketProtocol_UDP 548 | } 549 | 550 | func (x *Message) GetQueryAddress() []byte { 551 | if x != nil { 552 | return x.QueryAddress 553 | } 554 | return nil 555 | } 556 | 557 | func (x *Message) GetResponseAddress() []byte { 558 | if x != nil { 559 | return x.ResponseAddress 560 | } 561 | return nil 562 | } 563 | 564 | func (x *Message) GetQueryPort() uint32 { 565 | if x != nil && x.QueryPort != nil { 566 | return *x.QueryPort 567 | } 568 | return 0 569 | } 570 | 571 | func (x *Message) GetResponsePort() uint32 { 572 | if x != nil && x.ResponsePort != nil { 573 | return *x.ResponsePort 574 | } 575 | return 0 576 | } 577 | 578 | func (x *Message) GetQueryTimeSec() uint64 { 579 | if x != nil && x.QueryTimeSec != nil { 580 | return *x.QueryTimeSec 581 | } 582 | return 0 583 | } 584 | 585 | func (x *Message) GetQueryTimeNsec() uint32 { 586 | if x != nil && x.QueryTimeNsec != nil { 587 | return *x.QueryTimeNsec 588 | } 589 | return 0 590 | } 591 | 592 | func (x *Message) GetQueryMessage() []byte { 593 | if x != nil { 594 | return x.QueryMessage 595 | } 596 | return nil 597 | } 598 | 599 | func (x *Message) GetQueryZone() []byte { 600 | if x != nil { 601 | return x.QueryZone 602 | } 603 | return nil 604 | } 605 | 606 | func (x *Message) GetResponseTimeSec() uint64 { 607 | if x != nil && x.ResponseTimeSec != nil { 608 | return *x.ResponseTimeSec 609 | } 610 | return 0 611 | } 612 | 613 | func (x *Message) GetResponseTimeNsec() uint32 { 614 | if x != nil && x.ResponseTimeNsec != nil { 615 | return *x.ResponseTimeNsec 616 | } 617 | return 0 618 | } 619 | 620 | func (x *Message) GetResponseMessage() []byte { 621 | if x != nil { 622 | return x.ResponseMessage 623 | } 624 | return nil 625 | } 626 | 627 | var File_dnstap_proto protoreflect.FileDescriptor 628 | 629 | var file_dnstap_proto_rawDesc = []byte{ 630 | 0x0a, 0x0c, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 631 | 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x22, 0xbd, 0x01, 0x0a, 0x06, 0x44, 0x6e, 0x73, 0x74, 0x61, 632 | 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 633 | 0x01, 0x28, 0x0c, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x18, 0x0a, 634 | 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 635 | 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 636 | 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x65, 0x78, 0x74, 0x72, 0x61, 0x12, 0x27, 0x0a, 637 | 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0f, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x64, 0x6e, 638 | 0x73, 0x74, 0x61, 0x70, 0x2e, 0x44, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2e, 0x54, 0x79, 0x70, 0x65, 639 | 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 640 | 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 641 | 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 642 | 0x65, 0x22, 0x13, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x45, 0x53, 643 | 0x53, 0x41, 0x47, 0x45, 0x10, 0x01, 0x22, 0xf2, 0x06, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 644 | 0x67, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 645 | 0x32, 0x14, 0x2e, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 646 | 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0d, 647 | 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x02, 0x20, 648 | 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2e, 0x53, 0x6f, 0x63, 649 | 0x6b, 0x65, 0x74, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x52, 0x0c, 0x73, 0x6f, 0x63, 0x6b, 0x65, 650 | 0x74, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x0f, 0x73, 0x6f, 0x63, 0x6b, 0x65, 651 | 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 652 | 0x32, 0x16, 0x2e, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 653 | 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x0e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 654 | 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x72, 655 | 0x79, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 656 | 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x29, 0x0a, 657 | 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 658 | 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 659 | 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 660 | 0x79, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x71, 0x75, 661 | 0x65, 0x72, 0x79, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 662 | 0x6e, 0x73, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 663 | 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x0e, 664 | 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x08, 665 | 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x53, 666 | 0x65, 0x63, 0x12, 0x26, 0x0a, 0x0f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x74, 0x69, 0x6d, 0x65, 667 | 0x5f, 0x6e, 0x73, 0x65, 0x63, 0x18, 0x09, 0x20, 0x01, 0x28, 0x07, 0x52, 0x0d, 0x71, 0x75, 0x65, 668 | 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x65, 0x63, 0x12, 0x23, 0x0a, 0x0d, 0x71, 0x75, 669 | 0x65, 0x72, 0x79, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 670 | 0x0c, 0x52, 0x0c, 0x71, 0x75, 0x65, 0x72, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 671 | 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x0b, 0x20, 672 | 0x01, 0x28, 0x0c, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5a, 0x6f, 0x6e, 0x65, 0x12, 0x2a, 673 | 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 674 | 0x73, 0x65, 0x63, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 675 | 0x6e, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 676 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6e, 0x73, 0x65, 0x63, 677 | 0x18, 0x0d, 0x20, 0x01, 0x28, 0x07, 0x52, 0x10, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 678 | 0x54, 0x69, 0x6d, 0x65, 0x4e, 0x73, 0x65, 0x63, 0x12, 0x29, 0x0a, 0x10, 0x72, 0x65, 0x73, 0x70, 679 | 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x0e, 0x20, 0x01, 680 | 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 681 | 0x61, 0x67, 0x65, 0x22, 0x95, 0x02, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 682 | 0x41, 0x55, 0x54, 0x48, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 683 | 0x41, 0x55, 0x54, 0x48, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x02, 0x12, 684 | 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 0x51, 0x55, 0x45, 0x52, 685 | 0x59, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x53, 0x4f, 0x4c, 0x56, 0x45, 0x52, 0x5f, 686 | 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x04, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x4c, 687 | 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 688 | 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 689 | 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x46, 0x4f, 0x52, 0x57, 0x41, 0x52, 0x44, 0x45, 0x52, 0x5f, 0x51, 690 | 0x55, 0x45, 0x52, 0x59, 0x10, 0x07, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x4f, 0x52, 0x57, 0x41, 0x52, 691 | 0x44, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x08, 0x12, 0x0e, 692 | 0x0a, 0x0a, 0x53, 0x54, 0x55, 0x42, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 0x09, 0x12, 0x11, 693 | 0x0a, 0x0d, 0x53, 0x54, 0x55, 0x42, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 694 | 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x4f, 0x4f, 0x4c, 0x5f, 0x51, 0x55, 0x45, 0x52, 0x59, 0x10, 695 | 0x0b, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x4f, 0x4f, 0x4c, 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 696 | 0x53, 0x45, 0x10, 0x0c, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x51, 697 | 0x55, 0x45, 0x52, 0x59, 0x10, 0x0d, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 698 | 0x5f, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x10, 0x0e, 0x2a, 0x23, 0x0a, 0x0c, 0x53, 699 | 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x49, 700 | 0x4e, 0x45, 0x54, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x45, 0x54, 0x36, 0x10, 0x02, 701 | 0x2a, 0x34, 0x0a, 0x0e, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 702 | 0x6f, 0x6c, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 703 | 0x43, 0x50, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x44, 0x4f, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 704 | 0x03, 0x44, 0x4f, 0x48, 0x10, 0x04, 0x42, 0x28, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 705 | 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 706 | 0x6e, 0x67, 0x2d, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 0x3b, 0x64, 0x6e, 0x73, 0x74, 0x61, 0x70, 707 | } 708 | 709 | var ( 710 | file_dnstap_proto_rawDescOnce sync.Once 711 | file_dnstap_proto_rawDescData = file_dnstap_proto_rawDesc 712 | ) 713 | 714 | func file_dnstap_proto_rawDescGZIP() []byte { 715 | file_dnstap_proto_rawDescOnce.Do(func() { 716 | file_dnstap_proto_rawDescData = protoimpl.X.CompressGZIP(file_dnstap_proto_rawDescData) 717 | }) 718 | return file_dnstap_proto_rawDescData 719 | } 720 | 721 | var file_dnstap_proto_enumTypes = make([]protoimpl.EnumInfo, 4) 722 | var file_dnstap_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 723 | var file_dnstap_proto_goTypes = []interface{}{ 724 | (SocketFamily)(0), // 0: dnstap.SocketFamily 725 | (SocketProtocol)(0), // 1: dnstap.SocketProtocol 726 | (Dnstap_Type)(0), // 2: dnstap.Dnstap.Type 727 | (Message_Type)(0), // 3: dnstap.Message.Type 728 | (*Dnstap)(nil), // 4: dnstap.Dnstap 729 | (*Message)(nil), // 5: dnstap.Message 730 | } 731 | var file_dnstap_proto_depIdxs = []int32{ 732 | 2, // 0: dnstap.Dnstap.type:type_name -> dnstap.Dnstap.Type 733 | 5, // 1: dnstap.Dnstap.message:type_name -> dnstap.Message 734 | 3, // 2: dnstap.Message.type:type_name -> dnstap.Message.Type 735 | 0, // 3: dnstap.Message.socket_family:type_name -> dnstap.SocketFamily 736 | 1, // 4: dnstap.Message.socket_protocol:type_name -> dnstap.SocketProtocol 737 | 5, // [5:5] is the sub-list for method output_type 738 | 5, // [5:5] is the sub-list for method input_type 739 | 5, // [5:5] is the sub-list for extension type_name 740 | 5, // [5:5] is the sub-list for extension extendee 741 | 0, // [0:5] is the sub-list for field type_name 742 | } 743 | 744 | func init() { file_dnstap_proto_init() } 745 | func file_dnstap_proto_init() { 746 | if File_dnstap_proto != nil { 747 | return 748 | } 749 | if !protoimpl.UnsafeEnabled { 750 | file_dnstap_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 751 | switch v := v.(*Dnstap); i { 752 | case 0: 753 | return &v.state 754 | case 1: 755 | return &v.sizeCache 756 | case 2: 757 | return &v.unknownFields 758 | default: 759 | return nil 760 | } 761 | } 762 | file_dnstap_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 763 | switch v := v.(*Message); i { 764 | case 0: 765 | return &v.state 766 | case 1: 767 | return &v.sizeCache 768 | case 2: 769 | return &v.unknownFields 770 | default: 771 | return nil 772 | } 773 | } 774 | } 775 | type x struct{} 776 | out := protoimpl.TypeBuilder{ 777 | File: protoimpl.DescBuilder{ 778 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 779 | RawDescriptor: file_dnstap_proto_rawDesc, 780 | NumEnums: 4, 781 | NumMessages: 2, 782 | NumExtensions: 0, 783 | NumServices: 0, 784 | }, 785 | GoTypes: file_dnstap_proto_goTypes, 786 | DependencyIndexes: file_dnstap_proto_depIdxs, 787 | EnumInfos: file_dnstap_proto_enumTypes, 788 | MessageInfos: file_dnstap_proto_msgTypes, 789 | }.Build() 790 | File_dnstap_proto = out.File 791 | file_dnstap_proto_rawDesc = nil 792 | file_dnstap_proto_goTypes = nil 793 | file_dnstap_proto_depIdxs = nil 794 | } 795 | --------------------------------------------------------------------------------