├── .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 |
--------------------------------------------------------------------------------