Codebase list golang-github-dnstap-golang-dnstap / a526317
New upstream version 0.0~git20190601.0b64a38 Sascha Steinbiss 4 years ago
23 changed file(s) with 2943 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 *.swp
0 Copyright (c) 2013-2014 by Farsight Security, Inc.
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
0 /*
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
16 package dnstap
17
18 import (
19 "io"
20 "log"
21 "os"
22 "time"
23
24 "github.com/farsightsec/golang-framestream"
25 )
26
27 // MaxPayloadSize sets the upper limit on input Dnstap payload sizes. If an Input
28 // receives a Dnstap payload over this size limit, ReadInto will log an error and
29 // return.
30 //
31 // EDNS0 and DNS over TCP use 2 octets for DNS message size, imposing a maximum
32 // size of 65535 octets for the DNS message, which is the bulk of the data carried
33 // in a Dnstap message. Protobuf encoding overhead and metadata with some size
34 // guidance (e.g., identity and version being DNS strings, which have a maximum
35 // length of 255) add up to less than 1KB. The default 96KiB size of the buffer
36 // allows a bit over 30KB space for "extra" metadata.
37 //
38 var MaxPayloadSize uint32 = 96 * 1024
39
40 // A FrameStreamInput reads dnstap data from an io.ReadWriter.
41 type FrameStreamInput struct {
42 wait chan bool
43 decoder *framestream.Decoder
44 timeout time.Duration
45 }
46
47 // NewFrameStreamInput creates a FrameStreamInput reading data from the given
48 // io.ReadWriter. If bi is true, the input will use the bidirectional
49 // framestream protocol suitable for TCP and unix domain socket connections.
50 func NewFrameStreamInput(r io.ReadWriter, bi bool) (input *FrameStreamInput, err error) {
51 return NewFrameStreamInputTimeout(r, bi, 0)
52 }
53
54 // NewFrameStreamInputTimeout creates a FramestreamInput reading data from the
55 // given io.ReadWriter with a timeout applied to reading and (for bidirectional
56 // inputs) writing control messages.
57 func NewFrameStreamInputTimeout(r io.ReadWriter, bi bool, timeout time.Duration) (input *FrameStreamInput, err error) {
58 input = new(FrameStreamInput)
59 decoderOptions := framestream.DecoderOptions{
60 MaxPayloadSize: MaxPayloadSize,
61 ContentType: FSContentType,
62 Bidirectional: bi,
63 Timeout: timeout,
64 }
65 input.decoder, err = framestream.NewDecoder(r, &decoderOptions)
66 if err != nil {
67 return
68 }
69 input.wait = make(chan bool)
70 return
71 }
72
73 // NewFrameStreamInputFromFilename creates a FrameStreamInput reading from
74 // the named file.
75 func NewFrameStreamInputFromFilename(fname string) (input *FrameStreamInput, err error) {
76 file, err := os.Open(fname)
77 if err != nil {
78 return nil, err
79 }
80 input, err = NewFrameStreamInput(file, false)
81 return
82 }
83
84 // ReadInto reads data from the FrameStreamInput into the output channel.
85 //
86 // ReadInto satisfies the dnstap Input interface.
87 func (input *FrameStreamInput) ReadInto(output chan []byte) {
88 for {
89 buf, err := input.decoder.Decode()
90 if err != nil {
91 if err != io.EOF {
92 log.Printf("framestream.Decoder.Decode() failed: %s\n", err)
93 }
94 break
95 }
96 newbuf := make([]byte, len(buf))
97 copy(newbuf, buf)
98 output <- newbuf
99 }
100 close(input.wait)
101 }
102
103 // Wait reeturns when ReadInto has finished.
104 //
105 // Wait satisfies the dnstap Input interface.
106 func (input *FrameStreamInput) Wait() {
107 <-input.wait
108 }
0 /*
1 * Copyright (c) 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
16 package dnstap
17
18 import (
19 "io"
20 "log"
21 "os"
22
23 "github.com/farsightsec/golang-framestream"
24 )
25
26 // FrameStreamOutput implements a dnstap Output to an io.Writer.
27 type FrameStreamOutput struct {
28 outputChannel chan []byte
29 wait chan bool
30 enc *framestream.Encoder
31 }
32
33 // NewFrameStreamOutput creates a FrameStreamOutput writing dnstap data to
34 // the given io.Writer.
35 func NewFrameStreamOutput(w io.Writer) (o *FrameStreamOutput, err error) {
36 o = new(FrameStreamOutput)
37 o.outputChannel = make(chan []byte, outputChannelSize)
38 o.enc, err = framestream.NewEncoder(w, &framestream.EncoderOptions{ContentType: FSContentType})
39 if err != nil {
40 return
41 }
42 o.wait = make(chan bool)
43 return
44 }
45
46 // NewFrameStreamOutputFromFilename creates a file with the namee fname,
47 // truncates it if it exists, and returns a FrameStreamOutput writing to
48 // the newly created or truncated file.
49 func NewFrameStreamOutputFromFilename(fname string) (o *FrameStreamOutput, err error) {
50 if fname == "" || fname == "-" {
51 return NewFrameStreamOutput(os.Stdout)
52 }
53 w, err := os.Create(fname)
54 if err != nil {
55 return
56 }
57 return NewFrameStreamOutput(w)
58 }
59
60 // GetOutputChannel returns the channel on which the FrameStreamOutput accepts
61 // data.
62 //
63 // GetOutputData satisfies the dnstap Output interface.
64 func (o *FrameStreamOutput) GetOutputChannel() chan []byte {
65 return o.outputChannel
66 }
67
68 // RunOutputLoop processes data received on the channel returned by
69 // GetOutputChannel, returning after the CLose method is called.
70 // If there is an error writing to the Output's writer, RunOutputLoop()
71 // logs a fatal error exits the program.
72 //
73 // RunOutputLoop satisfies the dnstap Output interface.
74 func (o *FrameStreamOutput) RunOutputLoop() {
75 for frame := range o.outputChannel {
76 if _, err := o.enc.Write(frame); err != nil {
77 log.Fatalf("framestream.Encoder.Write() failed: %s\n", err)
78 break
79 }
80 }
81 close(o.wait)
82 }
83
84 // Close closes the channel returned from GetOutputChannel, and flushes
85 // all pending output.
86 //
87 // Close satisifies the dnstap Output interface.
88 func (o *FrameStreamOutput) Close() {
89 close(o.outputChannel)
90 <-o.wait
91 o.enc.Flush()
92 o.enc.Close()
93 }
0 /*
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
16 package dnstap
17
18 import (
19 "log"
20 "net"
21 "os"
22 "time"
23 )
24
25 // A FrameStreamSockInput collects dnstap data from one or more clients of
26 // a listening socket.
27 type FrameStreamSockInput struct {
28 wait chan bool
29 listener net.Listener
30 timeout time.Duration
31 }
32
33 // NewFrameStreamSockInput creates a FrameStreamSockInput collecting dnstap
34 // data from clients which connect to the given listener.
35 func NewFrameStreamSockInput(listener net.Listener) (input *FrameStreamSockInput) {
36 input = new(FrameStreamSockInput)
37 input.listener = listener
38 return
39 }
40
41 // SetTimeout sets the timeout for reading the initial handshake and writing
42 // response control messages to clients of the FrameStreamSockInput's listener.
43 //
44 // The timeout is effective only for connections accepted after the call to
45 // FrameStreamSockInput.
46 func (input *FrameStreamSockInput) SetTimeout(timeout time.Duration) {
47 input.timeout = timeout
48 }
49
50 // NewFrameStreamSockInputFromPath creates a unix domain socket at the
51 // given socketPath and returns a FrameStreamSockInput collecting dnstap
52 // data from clients connecting to this socket.
53 //
54 // If a socket or other file already exists at socketPath,
55 // NewFrameStreamSockInputFromPath removes it before creating the socket.
56 func NewFrameStreamSockInputFromPath(socketPath string) (input *FrameStreamSockInput, err error) {
57 os.Remove(socketPath)
58 listener, err := net.Listen("unix", socketPath)
59 if err != nil {
60 return
61 }
62 return NewFrameStreamSockInput(listener), nil
63 }
64
65 // ReadInto accepts connections to the FrameStreamSockInput's listening
66 // socket and sends all dnstap data read from these connections to the
67 // output channel.
68 //
69 // ReadInto satisfies the dnstap Input interface.
70 func (input *FrameStreamSockInput) ReadInto(output chan []byte) {
71 for {
72 conn, err := input.listener.Accept()
73 if err != nil {
74 log.Printf("net.Listener.Accept() failed: %s\n", err)
75 continue
76 }
77 i, err := NewFrameStreamInputTimeout(conn, true, input.timeout)
78 if err != nil {
79 log.Printf("dnstap.NewFrameStreamInput() failed: %s\n", err)
80 continue
81 }
82 log.Printf("dnstap.FrameStreamSockInput: accepted a socket connection\n")
83 go i.ReadInto(output)
84 }
85 }
86
87 // Wait satisfies the dnstap Input interface.
88 //
89 // The FrameSTreamSocketInput Wait method never returns, because the
90 // corresponding Readinto method also never returns.
91 func (input *FrameStreamSockInput) Wait() {
92 select {}
93 }
0 /*
1 * Copyright (c) 2019 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
16 package dnstap
17
18 import (
19 "log"
20 "net"
21 "time"
22
23 "github.com/farsightsec/golang-framestream"
24 )
25
26 // A FrameStreamSockOutput manages a socket connection and sends dnstap
27 // data over a framestream connection on that socket.
28 type FrameStreamSockOutput struct {
29 outputChannel chan []byte
30 address net.Addr
31 wait chan bool
32 dialer *net.Dialer
33 timeout time.Duration
34 retry time.Duration
35 flushTimeout time.Duration
36 }
37
38 // NewFrameStreamSockOutput creates a FrameStreamSockOutput manaaging a
39 // connection to the given address.
40 func NewFrameStreamSockOutput(address net.Addr) (*FrameStreamSockOutput, error) {
41 return &FrameStreamSockOutput{
42 outputChannel: make(chan []byte, outputChannelSize),
43 address: address,
44 wait: make(chan bool),
45 retry: 10 * time.Second,
46 flushTimeout: 5 * time.Second,
47 dialer: &net.Dialer{
48 Timeout: 30 * time.Second,
49 },
50 }, nil
51 }
52
53 // SetTimeout sets the write timeout for data and control messages and the
54 // read timeout for handshake responses on the FrameStreamSockOutput's
55 // connection. The default timeout is zero, for no timeout.
56 func (o *FrameStreamSockOutput) SetTimeout(timeout time.Duration) {
57 o.timeout = timeout
58 }
59
60 // SetFlushTimeout sets the maximum time data will be kept in the output
61 // buffer.
62 //
63 // The default flush timeout is five seconds.
64 func (o *FrameStreamSockOutput) SetFlushTimeout(timeout time.Duration) {
65 o.flushTimeout = timeout
66 }
67
68 // SetRetryInterval specifies how long the FrameStreamSockOutput will wait
69 // before re-establishing a failed connection. The default retry interval
70 // is 10 seconds.
71 func (o *FrameStreamSockOutput) SetRetryInterval(retry time.Duration) {
72 o.retry = retry
73 }
74
75 // SetDialer replaces the default net.Dialer for re-establishing the
76 // the FrameStreamSockOutput connection. This can be used to set the
77 // timeout for connection establishment and enable keepalives
78 // new connections.
79 //
80 // FrameStreamSockOutput uses a default dialer with a 30 second
81 // timeout.
82 func (o *FrameStreamSockOutput) SetDialer(dialer *net.Dialer) {
83 o.dialer = dialer
84 }
85
86 // GetOutputChannel returns the channel on which the
87 // FrameStreamSockOutput accepts data.
88 //
89 // GetOutputChannel satisifes the dnstap Output interface.
90 func (o *FrameStreamSockOutput) GetOutputChannel() chan []byte {
91 return o.outputChannel
92 }
93
94 // A timedConn resets an associated timer on each Write to the underlying
95 // connection, and is used to implement the output's flush timeout.
96 type timedConn struct {
97 net.Conn
98 timer *time.Timer
99 timeout time.Duration
100
101 // idle is true if the timer has fired and we have consumed
102 // the time from its channel. We use this to prevent deadlocking
103 // when resetting or stopping an already fired timer.
104 idle bool
105 }
106
107 // SetIdle informs the timedConn that the associated timer is idle, i.e.
108 // it has fired and has not been reset.
109 func (t *timedConn) SetIdle() {
110 t.idle = true
111 }
112
113 // Stop stops the underlying timer, consuming any time value if the timer
114 // had fired before Stop was called.
115 func (t *timedConn) StopTimer() {
116 if !t.timer.Stop() && !t.idle {
117 <-t.timer.C
118 }
119 t.idle = true
120 }
121
122 func (t *timedConn) Write(b []byte) (int, error) {
123 t.StopTimer()
124 t.timer.Reset(t.timeout)
125 t.idle = false
126 return t.Conn.Write(b)
127 }
128
129 func (t *timedConn) Close() error {
130 t.StopTimer()
131 return t.Conn.Close()
132 }
133
134 // RunOutputLoop reads data from the output channel and sends it over
135 // a connections to the FrameStreamSockOutput's address, establishing
136 // the connection as needed.
137 //
138 // RunOutputLoop satisifes the dnstap Output interface.
139 func (o *FrameStreamSockOutput) RunOutputLoop() {
140 var enc *framestream.Encoder
141 var err error
142
143 // Start with the connection flush timer in a stopped state.
144 // It will be reset by the first Write call on a new connection.
145 conn := &timedConn{
146 timer: time.NewTimer(0),
147 timeout: o.flushTimeout,
148 }
149 conn.StopTimer()
150
151 defer func() {
152 if enc != nil {
153 enc.Flush()
154 enc.Close()
155 }
156 if conn != nil {
157 conn.Close()
158 }
159 close(o.wait)
160 }()
161
162 for {
163 select {
164 case frame, ok := <-o.outputChannel:
165 if !ok {
166 return
167 }
168
169 // the retry loop
170 for ;; time.Sleep(o.retry) {
171 if enc == nil {
172 // connect the socket
173 conn.Conn, err = o.dialer.Dial(o.address.Network(), o.address.String())
174 if err != nil {
175 log.Printf("Dial() failed: %v", err)
176 continue // = retry
177 }
178
179 // create the encoder
180 eopt := framestream.EncoderOptions{
181 ContentType: FSContentType,
182 Bidirectional: true,
183 Timeout: o.timeout,
184 }
185 enc, err = framestream.NewEncoder(conn, &eopt)
186 if err != nil {
187 log.Printf("framestream.NewEncoder() failed: %v", err)
188 conn.Close()
189 enc = nil
190 continue // = retry
191 }
192 }
193
194 // try writing
195 if _, err = enc.Write(frame); err != nil {
196 log.Printf("framestream.Encoder.Write() failed: %v", err)
197 enc.Close()
198 enc = nil
199 conn.Close()
200 continue // = retry
201 }
202
203 break // success!
204 }
205
206 case <-conn.timer.C:
207 conn.SetIdle()
208 if enc == nil {
209 continue
210 }
211 if err := enc.Flush(); err != nil {
212 log.Printf("framestream.Encoder.Flush() failed: %s", err)
213 enc.Close()
214 enc = nil
215 conn.Close()
216 time.Sleep(o.retry)
217 }
218 }
219 }
220 }
221
222 // Close shuts down the FrameStreamSockOutput's output channel and returns
223 // after all pending data has been flushed and the connection has been closed.
224 //
225 // Close satisifes the dnstap Output interface
226 func (o *FrameStreamSockOutput) Close() {
227 close(o.outputChannel)
228 <-o.wait
229 }
0 /*
1 * Licensed under the Apache License, Version 2.0 (the "License");
2 * you may not use this file except in compliance with the License.
3 * You may obtain a copy of the License at
4 *
5 * http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13
14 package dnstap
15
16 import (
17 "bytes"
18 "encoding/json"
19 "fmt"
20 "net"
21 "time"
22
23 "github.com/miekg/dns"
24 )
25
26 type jsonTime time.Time
27
28 func (jt *jsonTime) MarshalJSON() ([]byte, error) {
29 stamp := time.Time(*jt).Format(time.RFC3339Nano)
30 return []byte(fmt.Sprintf("\"%s\"", stamp)), nil
31 }
32
33 type jsonDnstap struct {
34 Type string `json:"type"`
35 Identity string `json:"identity,omitempty"`
36 Version string `json:"version,omitempty"`
37 Message jsonMessage `json:"message"`
38 }
39
40 type jsonMessage struct {
41 Type string `json:"type"`
42 QueryTime *jsonTime `json:"query_time,omitempty"`
43 ResponseTime *jsonTime `json:"response_time,omitempty"`
44 SocketFamily string `json:"socket_family,omitempty"`
45 SocketProtocol string `json:"socket_protocol,omitempty"`
46 QueryAddress *net.IP `json:"query_address,omitempty"`
47 ResponseAddress *net.IP `json:"response_address,omitempty"`
48 QueryPort uint32 `json:"query_port,omitempty"`
49 ResponsePort uint32 `json:"response_port,omitempty"`
50 QueryZone string `json:"query_zone,omitempty"`
51 QueryMessage string `json:"query_message,omitempty"`
52 ResponseMessage string `json:"response_message,omitempty"`
53 }
54
55 func convertJSONMessage(m *Message) jsonMessage {
56 jMsg := jsonMessage{
57 Type: fmt.Sprint(m.Type),
58 SocketFamily: fmt.Sprint(m.SocketFamily),
59 SocketProtocol: fmt.Sprint(m.SocketProtocol),
60 }
61
62 if m.QueryTimeSec != nil && m.QueryTimeNsec != nil {
63 qt := jsonTime(time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC())
64 jMsg.QueryTime = &qt
65 }
66
67 if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil {
68 rt := jsonTime(time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC())
69 jMsg.ResponseTime = &rt
70 }
71
72 if m.QueryAddress != nil {
73 qa := net.IP(m.QueryAddress)
74 jMsg.QueryAddress = &qa
75 }
76
77 if m.ResponseAddress != nil {
78 ra := net.IP(m.ResponseAddress)
79 jMsg.ResponseAddress = &ra
80 }
81
82 if m.QueryPort != nil {
83 jMsg.QueryPort = *m.QueryPort
84 }
85
86 if m.ResponsePort != nil {
87 jMsg.ResponsePort = *m.ResponsePort
88 }
89
90 if m.QueryZone != nil {
91 name, _, err := dns.UnpackDomainName(m.QueryZone, 0)
92 if err != nil {
93 jMsg.QueryZone = fmt.Sprintf("parse failed: %v", err)
94 } else {
95 jMsg.QueryZone = string(name)
96 }
97 }
98
99 if m.QueryMessage != nil {
100 msg := new(dns.Msg)
101 err := msg.Unpack(m.QueryMessage)
102 if err != nil {
103 jMsg.QueryMessage = fmt.Sprintf("parse failed: %v", err)
104 } else {
105 jMsg.QueryMessage = msg.String()
106 }
107 }
108
109 if m.ResponseMessage != nil {
110 msg := new(dns.Msg)
111 err := msg.Unpack(m.ResponseMessage)
112 if err != nil {
113 jMsg.ResponseMessage = fmt.Sprintf("parse failed: %v", err)
114 } else {
115 jMsg.ResponseMessage = msg.String()
116 }
117 }
118 return jMsg
119 }
120
121 // JSONFormat renders a Dnstap message in JSON format. Any encapsulated
122 // DNS messages are rendered as strings in a format similar to 'dig' output.
123 func JSONFormat(dt *Dnstap) (out []byte, ok bool) {
124 var s bytes.Buffer
125
126 j, err := json.Marshal(jsonDnstap{
127 Type: fmt.Sprint(dt.Type),
128 Identity: string(dt.Identity),
129 Version: string(dt.Version),
130 Message: convertJSONMessage(dt.Message),
131 })
132 if err != nil {
133 return nil, false
134 }
135
136 s.WriteString(string(j) + "\n")
137
138 return s.Bytes(), true
139 }
0
1 Apache License
2 Version 2.0, January 2004
3 http://www.apache.org/licenses/
4
5 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
7 1. Definitions.
8
9 "License" shall mean the terms and conditions for use, reproduction,
10 and distribution as defined by Sections 1 through 9 of this document.
11
12 "Licensor" shall mean the copyright owner or entity authorized by
13 the copyright owner that is granting the License.
14
15 "Legal Entity" shall mean the union of the acting entity and all
16 other entities that control, are controlled by, or are under common
17 control with that entity. For the purposes of this definition,
18 "control" means (i) the power, direct or indirect, to cause the
19 direction or management of such entity, whether by contract or
20 otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 outstanding shares, or (iii) beneficial ownership of such entity.
22
23 "You" (or "Your") shall mean an individual or Legal Entity
24 exercising permissions granted by this License.
25
26 "Source" form shall mean the preferred form for making modifications,
27 including but not limited to software source code, documentation
28 source, and configuration files.
29
30 "Object" form shall mean any form resulting from mechanical
31 transformation or translation of a Source form, including but
32 not limited to compiled object code, generated documentation,
33 and conversions to other media types.
34
35 "Work" shall mean the work of authorship, whether in Source or
36 Object form, made available under the License, as indicated by a
37 copyright notice that is included in or attached to the work
38 (an example is provided in the Appendix below).
39
40 "Derivative Works" shall mean any work, whether in Source or Object
41 form, that is based on (or derived from) the Work and for which the
42 editorial revisions, annotations, elaborations, or other modifications
43 represent, as a whole, an original work of authorship. For the purposes
44 of this License, Derivative Works shall not include works that remain
45 separable from, or merely link (or bind by name) to the interfaces of,
46 the Work and Derivative Works thereof.
47
48 "Contribution" shall mean any work of authorship, including
49 the original version of the Work and any modifications or additions
50 to that Work or Derivative Works thereof, that is intentionally
51 submitted to Licensor for inclusion in the Work by the copyright owner
52 or by an individual or Legal Entity authorized to submit on behalf of
53 the copyright owner. For the purposes of this definition, "submitted"
54 means any form of electronic, verbal, or written communication sent
55 to the Licensor or its representatives, including but not limited to
56 communication on electronic mailing lists, source code control systems,
57 and issue tracking systems that are managed by, or on behalf of, the
58 Licensor for the purpose of discussing and improving the Work, but
59 excluding communication that is conspicuously marked or otherwise
60 designated in writing by the copyright owner as "Not a Contribution."
61
62 "Contributor" shall mean Licensor and any individual or Legal Entity
63 on behalf of whom a Contribution has been received by Licensor and
64 subsequently incorporated within the Work.
65
66 2. Grant of Copyright License. Subject to the terms and conditions of
67 this License, each Contributor hereby grants to You a perpetual,
68 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 copyright license to reproduce, prepare Derivative Works of,
70 publicly display, publicly perform, sublicense, and distribute the
71 Work and such Derivative Works in Source or Object form.
72
73 3. Grant of Patent License. Subject to the terms and conditions of
74 this License, each Contributor hereby grants to You a perpetual,
75 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 (except as stated in this section) patent license to make, have made,
77 use, offer to sell, sell, import, and otherwise transfer the Work,
78 where such license applies only to those patent claims licensable
79 by such Contributor that are necessarily infringed by their
80 Contribution(s) alone or by combination of their Contribution(s)
81 with the Work to which such Contribution(s) was submitted. If You
82 institute patent litigation against any entity (including a
83 cross-claim or counterclaim in a lawsuit) alleging that the Work
84 or a Contribution incorporated within the Work constitutes direct
85 or contributory patent infringement, then any patent licenses
86 granted to You under this License for that Work shall terminate
87 as of the date such litigation is filed.
88
89 4. Redistribution. You may reproduce and distribute copies of the
90 Work or Derivative Works thereof in any medium, with or without
91 modifications, and in Source or Object form, provided that You
92 meet the following conditions:
93
94 (a) You must give any other recipients of the Work or
95 Derivative Works a copy of this License; and
96
97 (b) You must cause any modified files to carry prominent notices
98 stating that You changed the files; and
99
100 (c) You must retain, in the Source form of any Derivative Works
101 that You distribute, all copyright, patent, trademark, and
102 attribution notices from the Source form of the Work,
103 excluding those notices that do not pertain to any part of
104 the Derivative Works; and
105
106 (d) If the Work includes a "NOTICE" text file as part of its
107 distribution, then any Derivative Works that You distribute must
108 include a readable copy of the attribution notices contained
109 within such NOTICE file, excluding those notices that do not
110 pertain to any part of the Derivative Works, in at least one
111 of the following places: within a NOTICE text file distributed
112 as part of the Derivative Works; within the Source form or
113 documentation, if provided along with the Derivative Works; or,
114 within a display generated by the Derivative Works, if and
115 wherever such third-party notices normally appear. The contents
116 of the NOTICE file are for informational purposes only and
117 do not modify the License. You may add Your own attribution
118 notices within Derivative Works that You distribute, alongside
119 or as an addendum to the NOTICE text from the Work, provided
120 that such additional attribution notices cannot be construed
121 as modifying the License.
122
123 You may add Your own copyright statement to Your modifications and
124 may provide additional or different license terms and conditions
125 for use, reproduction, or distribution of Your modifications, or
126 for any such Derivative Works as a whole, provided Your use,
127 reproduction, and distribution of the Work otherwise complies with
128 the conditions stated in this License.
129
130 5. Submission of Contributions. Unless You explicitly state otherwise,
131 any Contribution intentionally submitted for inclusion in the Work
132 by You to the Licensor shall be under the terms and conditions of
133 this License, without any additional terms or conditions.
134 Notwithstanding the above, nothing herein shall supersede or modify
135 the terms of any separate license agreement you may have executed
136 with Licensor regarding such Contributions.
137
138 6. Trademarks. This License does not grant permission to use the trade
139 names, trademarks, service marks, or product names of the Licensor,
140 except as required for reasonable and customary use in describing the
141 origin of the Work and reproducing the content of the NOTICE file.
142
143 7. Disclaimer of Warranty. Unless required by applicable law or
144 agreed to in writing, Licensor provides the Work (and each
145 Contributor provides its Contributions) on an "AS IS" BASIS,
146 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 implied, including, without limitation, any warranties or conditions
148 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 PARTICULAR PURPOSE. You are solely responsible for determining the
150 appropriateness of using or redistributing the Work and assume any
151 risks associated with Your exercise of permissions under this License.
152
153 8. Limitation of Liability. In no event and under no legal theory,
154 whether in tort (including negligence), contract, or otherwise,
155 unless required by applicable law (such as deliberate and grossly
156 negligent acts) or agreed to in writing, shall any Contributor be
157 liable to You for damages, including any direct, indirect, special,
158 incidental, or consequential damages of any character arising as a
159 result of this License or out of the use or inability to use the
160 Work (including but not limited to damages for loss of goodwill,
161 work stoppage, computer failure or malfunction, or any and all
162 other commercial damages or losses), even if such Contributor
163 has been advised of the possibility of such damages.
164
165 9. Accepting Warranty or Additional Liability. While redistributing
166 the Work or Derivative Works thereof, You may choose to offer,
167 and charge a fee for, acceptance of support, warranty, indemnity,
168 or other liability obligations and/or rights consistent with this
169 License. However, in accepting such obligations, You may act only
170 on Your own behalf and on Your sole responsibility, not on behalf
171 of any other Contributor, and only if You agree to indemnify,
172 defend, and hold each Contributor harmless for any liability
173 incurred by, or claims asserted against, such Contributor by reason
174 of your accepting any such warranty or additional liability.
175
176 END OF TERMS AND CONDITIONS
177
178 APPENDIX: How to apply the Apache License to your work.
179
180 To apply the Apache License to your work, attach the following
181 boilerplate notice, with the fields enclosed by brackets "[]"
182 replaced with your own identifying information. (Don't include
183 the brackets!) The text should be enclosed in the appropriate
184 comment syntax for the file format. We also recommend that a
185 file or class name and description of purpose be included on the
186 same "printed page" as the copyright notice for easier
187 identification within third-party archives.
188
189 Copyright [yyyy] [name of copyright owner]
190
191 Licensed under the Apache License, Version 2.0 (the "License");
192 you may not use this file except in compliance with the License.
193 You may obtain a copy of the License at
194
195 http://www.apache.org/licenses/LICENSE-2.0
196
197 Unless required by applicable law or agreed to in writing, software
198 distributed under the License is distributed on an "AS IS" BASIS,
199 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 See the License for the specific language governing permissions and
201 limitations under the License.
0 /*
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
16 package dnstap
17
18 import (
19 "bytes"
20 "fmt"
21 "net"
22 "strconv"
23 "time"
24
25 "github.com/miekg/dns"
26 )
27
28 const quietTimeFormat = "15:04:05"
29
30 func textConvertTime(s *bytes.Buffer, secs *uint64, nsecs *uint32) {
31 if secs != nil {
32 s.WriteString(time.Unix(int64(*secs), 0).Format(quietTimeFormat))
33 } else {
34 s.WriteString("??:??:??")
35 }
36 if nsecs != nil {
37 s.WriteString(fmt.Sprintf(".%06d", *nsecs/1000))
38 } else {
39 s.WriteString(".??????")
40 }
41 }
42
43 func textConvertIP(s *bytes.Buffer, ip []byte) {
44 if ip != nil {
45 s.WriteString(net.IP(ip).String())
46 } else {
47 s.WriteString("MISSING_ADDRESS")
48 }
49 }
50
51 func textConvertMessage(m *Message, s *bytes.Buffer) {
52 isQuery := false
53 printQueryAddress := false
54
55 switch *m.Type {
56 case Message_CLIENT_QUERY,
57 Message_RESOLVER_QUERY,
58 Message_AUTH_QUERY,
59 Message_FORWARDER_QUERY,
60 Message_TOOL_QUERY:
61 isQuery = true
62 case Message_CLIENT_RESPONSE,
63 Message_RESOLVER_RESPONSE,
64 Message_AUTH_RESPONSE,
65 Message_FORWARDER_RESPONSE,
66 Message_TOOL_RESPONSE:
67 isQuery = false
68 default:
69 s.WriteString("[unhandled Message.Type]\n")
70 return
71 }
72
73 if isQuery {
74 textConvertTime(s, m.QueryTimeSec, m.QueryTimeNsec)
75 } else {
76 textConvertTime(s, m.ResponseTimeSec, m.ResponseTimeNsec)
77 }
78 s.WriteString(" ")
79
80 switch *m.Type {
81 case Message_CLIENT_QUERY,
82 Message_CLIENT_RESPONSE:
83 {
84 s.WriteString("C")
85 }
86 case Message_RESOLVER_QUERY,
87 Message_RESOLVER_RESPONSE:
88 {
89 s.WriteString("R")
90 }
91 case Message_AUTH_QUERY,
92 Message_AUTH_RESPONSE:
93 {
94 s.WriteString("A")
95 }
96 case Message_FORWARDER_QUERY,
97 Message_FORWARDER_RESPONSE:
98 {
99 s.WriteString("F")
100 }
101 case Message_STUB_QUERY,
102 Message_STUB_RESPONSE:
103 {
104 s.WriteString("S")
105 }
106 case Message_TOOL_QUERY,
107 Message_TOOL_RESPONSE:
108 {
109 s.WriteString("T")
110 }
111 }
112
113 if isQuery {
114 s.WriteString("Q ")
115 } else {
116 s.WriteString("R ")
117 }
118
119 switch *m.Type {
120 case Message_CLIENT_QUERY,
121 Message_CLIENT_RESPONSE,
122 Message_AUTH_QUERY,
123 Message_AUTH_RESPONSE:
124 printQueryAddress = true
125 }
126
127 if printQueryAddress {
128 textConvertIP(s, m.QueryAddress)
129 } else {
130 textConvertIP(s, m.ResponseAddress)
131 }
132 s.WriteString(" ")
133
134 if m.SocketProtocol != nil {
135 s.WriteString(m.SocketProtocol.String())
136 }
137 s.WriteString(" ")
138
139 var err error
140 msg := new(dns.Msg)
141 if isQuery {
142 s.WriteString(strconv.Itoa(len(m.QueryMessage)))
143 s.WriteString("b ")
144 err = msg.Unpack(m.QueryMessage)
145 } else {
146 s.WriteString(strconv.Itoa(len(m.ResponseMessage)))
147 s.WriteString("b ")
148 err = msg.Unpack(m.ResponseMessage)
149 }
150
151 if err != nil || len(msg.Question) == 0 {
152 s.WriteString("X ")
153 } else {
154 s.WriteString("\"" + msg.Question[0].Name + "\" ")
155 s.WriteString(dns.Class(msg.Question[0].Qclass).String() + " ")
156 s.WriteString(dns.Type(msg.Question[0].Qtype).String())
157 }
158
159 s.WriteString("\n")
160 }
161
162 // TextFormat renders a dnstap message in a compact human-readable text
163 // form.
164 func TextFormat(dt *Dnstap) (out []byte, ok bool) {
165 var s bytes.Buffer
166
167 if *dt.Type == Dnstap_MESSAGE {
168 textConvertMessage(dt.Message, &s)
169 return s.Bytes(), true
170 }
171
172 return nil, false
173 }
0 dnstap: flexible, structured event replication format for DNS servers
1 ---------------------------------------------------------------------
2
3 dnstap implements an encoding format for DNS server events. It uses a
4 lightweight framing on top of event payloads encoded using Protocol Buffers and
5 is transport neutral.
6
7 dnstap can represent internal state inside a DNS server that is difficult to
8 obtain using techniques based on traditional packet capture or unstructured
9 textual format logging.
10
11 This repository contains a command-line tool named "dnstap" developed in the
12 Go programming language. It can be installed with the following command:
13
14 go get -u github.com/dnstap/golang-dnstap/dnstap
0 /*
1 * Copyright (c) 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
16 package dnstap
17
18 import (
19 "bufio"
20 "io"
21 "log"
22 "os"
23
24 "github.com/golang/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 }
37
38 // NewTextOutput creates a TextOutput writing dnstap data to the given io.Writer
39 // in the text format given by the TextFormatFunc format.
40 func NewTextOutput(writer io.Writer, format TextFormatFunc) (o *TextOutput) {
41 o = new(TextOutput)
42 o.format = format
43 o.outputChannel = make(chan []byte, outputChannelSize)
44 o.writer = bufio.NewWriter(writer)
45 o.wait = make(chan bool)
46 return
47 }
48
49 // NewTextOutputFromFilename creates a TextOutput writing dnstap data to a
50 // file with the given filename in the format given by format. If doAppend
51 // is false, the file is truncated if it already exists, otherwise the file
52 // is opened for appending.
53 func NewTextOutputFromFilename(fname string, format TextFormatFunc, doAppend bool) (o *TextOutput, err error) {
54 if fname == "" || fname == "-" {
55 return NewTextOutput(os.Stdout, format), nil
56 }
57 var writer io.Writer
58 if doAppend {
59 writer, err = os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
60 } else {
61 writer, err = os.Create(fname)
62 }
63 if err != nil {
64 return
65 }
66 return NewTextOutput(writer, format), nil
67 }
68
69 // GetOutputChannel returns the channel on which the TextOutput accepts dnstap data.
70 //
71 // GetOutputChannel satisfies the dnstap Output interface.
72 func (o *TextOutput) GetOutputChannel() chan []byte {
73 return o.outputChannel
74 }
75
76 // RunOutputLoop receives dnstap data sent on the output channel, formats it
77 // with the configured TextFormatFunc, and writes it to the file or io.Writer
78 // of the TextOutput.
79 //
80 // RunOutputLoop satisfies the dnstap Output interface.
81 func (o *TextOutput) RunOutputLoop() {
82 dt := &Dnstap{}
83 for frame := range o.outputChannel {
84 if err := proto.Unmarshal(frame, dt); err != nil {
85 log.Fatalf("dnstap.TextOutput: proto.Unmarshal() failed: %s\n", err)
86 break
87 }
88 buf, ok := o.format(dt)
89 if !ok {
90 log.Fatalf("dnstap.TextOutput: text format function failed\n")
91 break
92 }
93 if _, err := o.writer.Write(buf); err != nil {
94 log.Fatalf("dnstap.TextOutput: write failed: %s\n", err)
95 break
96 }
97 o.writer.Flush()
98 }
99 close(o.wait)
100 }
101
102 // Close closes the output channel and returns when all pending data has been
103 // written.
104 //
105 // Close satisfies the dnstap Output interface.
106 func (o *TextOutput) Close() {
107 close(o.outputChannel)
108 <-o.wait
109 o.writer.Flush()
110 }
0 /*
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
16 package dnstap
17
18 import (
19 "bytes"
20 "fmt"
21 "net"
22 "strconv"
23 "strings"
24 "time"
25
26 "github.com/miekg/dns"
27 )
28
29 const yamlTimeFormat = "2006-01-02 15:04:05.999999999"
30
31 func yamlConvertMessage(m *Message, s *bytes.Buffer) {
32 s.WriteString(fmt.Sprint(" type: ", m.Type, "\n"))
33
34 if m.QueryTimeSec != nil && m.QueryTimeNsec != nil {
35 t := time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC()
36 s.WriteString(fmt.Sprint(" query_time: !!timestamp ", t.Format(yamlTimeFormat), "\n"))
37 }
38
39 if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil {
40 t := time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC()
41 s.WriteString(fmt.Sprint(" response_time: !!timestamp ", t.Format(yamlTimeFormat), "\n"))
42 }
43
44 if m.SocketFamily != nil {
45 s.WriteString(fmt.Sprint(" socket_family: ", m.SocketFamily, "\n"))
46 }
47
48 if m.SocketProtocol != nil {
49 s.WriteString(fmt.Sprint(" socket_protocol: ", m.SocketProtocol, "\n"))
50 }
51
52 if m.QueryAddress != nil {
53 s.WriteString(fmt.Sprint(" query_address: ", net.IP(m.QueryAddress), "\n"))
54 }
55
56 if m.ResponseAddress != nil {
57 s.WriteString(fmt.Sprint(" response_address: ", net.IP(m.ResponseAddress), "\n"))
58 }
59
60 if m.QueryPort != nil {
61 s.WriteString(fmt.Sprint(" query_port: ", *m.QueryPort, "\n"))
62 }
63
64 if m.ResponsePort != nil {
65 s.WriteString(fmt.Sprint(" response_port: ", *m.ResponsePort, "\n"))
66 }
67
68 if m.QueryZone != nil {
69 name, _, err := dns.UnpackDomainName(m.QueryZone, 0)
70 if err != nil {
71 fmt.Fprintf(s, " # query_zone: parse failed: %v\n", err)
72 } else {
73 s.WriteString(fmt.Sprint(" query_zone: ", strconv.Quote(name), "\n"))
74 }
75 }
76
77 if m.QueryMessage != nil {
78 msg := new(dns.Msg)
79 err := msg.Unpack(m.QueryMessage)
80 if err != nil {
81 fmt.Fprintf(s, " # query_message: parse failed: %v\n", err)
82 } else {
83 s.WriteString(" query_message: |\n")
84 s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n")
85 }
86 }
87 if m.ResponseMessage != nil {
88 msg := new(dns.Msg)
89 err := msg.Unpack(m.ResponseMessage)
90 if err != nil {
91 fmt.Fprintf(s, " # response_message: parse failed: %v\n", err)
92 } else {
93 s.WriteString(" response_message: |\n")
94 s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n")
95 }
96 }
97 s.WriteString("---\n")
98 }
99
100 // YamlFormat renders a dnstap message in YAML format. Any encapsulated DNS
101 // messages are rendered as strings in a format similar to 'dig' output.
102 func YamlFormat(dt *Dnstap) (out []byte, ok bool) {
103 var s bytes.Buffer
104
105 s.WriteString(fmt.Sprint("type: ", dt.Type, "\n"))
106 if dt.Identity != nil {
107 s.WriteString(fmt.Sprint("identity: ", strconv.Quote(string(dt.Identity)), "\n"))
108 }
109 if dt.Version != nil {
110 s.WriteString(fmt.Sprint("version: ", strconv.Quote(string(dt.Version)), "\n"))
111 }
112 if *dt.Type == Dnstap_MESSAGE {
113 s.WriteString("message:\n")
114 yamlConvertMessage(dt.Message, &s)
115 }
116 return s.Bytes(), true
117 }
0 .TH dnstap 8
1
2 .SH NAME
3
4 dnstap \- Capture, display, and relay Dnstap data.
5
6 .SH SYNOPSIS
7
8 .B dnstap [ -u \fIsocket-path\fB [ -u \fIsocket2-path\fB ... ] ]
9 .br
10 .B " [ -l \fIhost:port\fB [ -l \fIhost2:port2\fB ... ] ]"
11 .br
12 .B " [ -r \fIfile\fB [ -r \fIfile2\fB ... ] ]"
13 .br
14 .B " [ -U \fIsocket-path\fB [ -U \fIsocket2-path\fB ... ] ]"
15 .br
16 .B " [ -T \fIhost:port\fB [ -T \fIhost2:port2\fB ... ] ]"
17 .br
18 .B " [ -w \fIfile\fB ] [ -q | -y | -j ] [-a]"
19 .br
20 .B " [ -t \fItimeout\fB ]"
21 .br
22
23 .SH DESCRIPTION
24
25 .B dnstap
26 reads data in the Dnstap export format from Frame Streams files or
27 receives data on Frame Streams connections to TCP/IP or unix domain
28 socket addresses.
29 .B dnstap
30 can display this data in a compact text (the default), JSON, or YAML
31 formats. It can also save data to a file in display or Frame Streams
32 binary format, or relay the data to other Dnstap processes over unix
33 domain socket or TCP/IP connections.
34
35 .SH OPTIONS
36
37 .TP
38 .B -a
39 When opening an file (\fB-w\fR) for text format output
40 (\fB-j\fR, \fB-q\fR, or \fB-y\fR), append to the file rather
41 truncating.
42
43 .B -a
44 does not apply when writing binary Frame Streams data to a file.
45
46 .TP
47 .B -j
48 Write data in JSON format. Encapsulated DNS messages are
49 rendered in text form similar to the output of \fBdig(1)\fR.
50
51 At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be
52 given.
53
54 .TP
55 .B -l \fIhost:port\fR
56 Listen for Dnstap data on TCP/IP port \fBport\fR on address \fIhost\fR.
57
58 The \fB-l\fR option may be given multiple times to listen on multiple
59 addresses.
60
61 At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given.
62
63 .TP
64 .B -q
65 Write or display data in compact (quiet) text format.
66
67 At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be given.
68
69 .TP
70 .B -r \fIfile\fR
71 Read Dnstap data from the given \fIfile\fR. The \fB-r\fR option
72 may be given multiple times to read from multiple files.
73
74 At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given.
75
76 .TP
77 .B -T \fIhost:port\fR
78 Relay Dnstap data over a TCP/IP connection to \fIhost:port\fR.
79 \fBdnstap\fR will establish or re-establish this connection as needed.
80
81 The \fB-T\fR option may be given multiple times to relay Dnstap data
82 to multiple addresses.
83
84 .TP
85 .B -t \fItimeout\fR
86 Apply i/o \fItimeout\fR to TCP/IP and unix domain socket
87 connections. \fItimeout\fR is given as a number followed by a unit
88 abbreviation (e.g., \fIms\fR for milliseconds, \fIs\fR for seconds,
89 \fIm\fR for minutes).
90
91 .TP
92 .B -u \fIsocket-path\fR
93 Listen for Dnstap data on the unix domain socket at
94 \fIsocket-path\fR. \fBdnstap\fR will remove any file or socket
95 \fIsocket-path\fR before listening.
96
97 The \fB-u\fR option may be given multiple times to listen on multiple
98 socket paths.
99
100 At least one input (\fB-l\fR, \fB-r\fR, or \fB-u\fR) option must be given.
101
102 .TP
103 .B -U \fIsocket-path\fR
104 Relay Dnstap data over a unix domain socket connection to
105 \fIsocket-path\fR. \fBdnstap\fR will establish or re-establish this
106 connection as needed.
107
108 The \fB-U\fR option may be given multiple times to relay Dnstap data to
109 multiple socket paths.
110
111
112 .TP
113 .B -w \fIfile\fR
114 Write Dnstap data to \fIfile\fR.
115
116 If \fIfile\fR is "-" or no \fB-w\fR, \fB-T\fR, or \fB-U\fR output
117 options are present, data will be written to standard output in quiet
118 text format (\fB-q\fR), unless the YAML or JSON format is specified
119 with the \fB-y\fR or \fB-j\fR options, respectively.
120
121 If \fIfile\fR is a filename other than "-", Dnstap data is written to the
122 named file in Frame Streams binary format by default, unless quiet text,
123 JSON, or YAML formats are specified.
124
125 .B dnstap
126 will reopen \fIfile\fR on \fBSIGHUP\fR, for file rotation purposes.
127
128
129 .TP
130 .B -y
131 Write Dnstap output in YAML format. Encapsulated DNS messages are rendered in text
132 form similar to the output of \fBdig(1)\fR.
133
134 At most one text format (\fB-j\fR, \fB-q\fR, or \fB-y\fR) option may be given.
135
136
137 .SH EXAMPLES
138
139 Listen for Dnstap data from a local name server and print quiet text format
140 to standard output.
141
142 .nf
143 dnstap -u /var/named/dnstap.sock
144 .fi
145
146 Listen for Dnstap data from a local name server, save a local binary copy, and
147 relay it to a remote host over TCP.
148
149 .nf
150 dnstap -u /usr/local/unbound/dnstap.sock -w dnstap.fstrm \\
151 -T dns-admin.example.com:5353
152 .fi
153
154 .SH SEE ALSO
155
156 .B dig(1)
0 /*
1 * Copyright (c) 2019 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
16 package main
17
18 import (
19 "errors"
20 "fmt"
21 "os"
22 "os/signal"
23 "syscall"
24
25 dnstap "github.com/dnstap/golang-dnstap"
26 )
27
28 // Output channel buffer size value from main dnstap package.
29 const outputChannelSize = 32
30
31 //
32 // A fileOutput implements a dnstap.Output which writes frames to a file
33 // and closes and reopens the file on SIGHUP.
34 //
35 // Data frames are written in binary fstrm format unless a text formatting
36 // function (dnstp.TextFormatFunc) is given or the filename is blank or "-".
37 // In the latter case, data is written in compact (quiet) text format unless
38 // an alternate text format is given on the assumption that stdout is a terminal.
39 //
40 type fileOutput struct {
41 formatter dnstap.TextFormatFunc
42 filename string
43 doAppend bool
44 output dnstap.Output
45 data chan []byte
46 done chan struct{}
47 }
48
49 func openOutputFile(filename string, formatter dnstap.TextFormatFunc, doAppend bool) (o dnstap.Output, err error) {
50 if formatter == nil {
51 if filename == "-" || filename == "" {
52 o = dnstap.NewTextOutput(os.Stdout, dnstap.TextFormat)
53 return
54 }
55 o, err = dnstap.NewFrameStreamOutputFromFilename(filename)
56 } else {
57 if filename == "-" || filename == "" {
58 if doAppend {
59 return nil, errors.New("cannot append to stdout (-)")
60 }
61 o = dnstap.NewTextOutput(os.Stdout, formatter)
62 return
63 }
64 o, err = dnstap.NewTextOutputFromFilename(filename, formatter, doAppend)
65 }
66 return
67 }
68
69 func newFileOutput(filename string, formatter dnstap.TextFormatFunc, doAppend bool) (*fileOutput, error) {
70 o, err := openOutputFile(filename, formatter, doAppend)
71 if err != nil {
72 return nil, err
73 }
74 return &fileOutput{
75 formatter: formatter,
76 filename: filename,
77 doAppend: doAppend,
78 output: o,
79 data: make(chan []byte, outputChannelSize),
80 done: make(chan struct{}),
81 }, nil
82 }
83
84 func (fo *fileOutput) GetOutputChannel() chan []byte {
85 return fo.data
86 }
87
88 func (fo *fileOutput) Close() {
89 close(fo.data)
90 <-fo.done
91 }
92
93 func (fo *fileOutput) RunOutputLoop() {
94 sigch := make(chan os.Signal, 1)
95 signal.Notify(sigch, os.Interrupt, syscall.SIGHUP)
96 o := fo.output
97 go o.RunOutputLoop()
98 defer func() {
99 o.Close()
100 close(fo.done)
101 }()
102 for {
103 select {
104 case b, ok := <-fo.data:
105 if !ok {
106 return
107 }
108 o.GetOutputChannel() <- b
109 case sig := <-sigch:
110 if sig == syscall.SIGHUP {
111 o.Close()
112 newo, err := openOutputFile(fo.filename, fo.formatter, fo.doAppend)
113 if err != nil {
114 fmt.Fprintf(os.Stderr,
115 "dnstap: Error: failed to reopen %s: %v\n",
116 fo.filename, err)
117 os.Exit(1)
118 }
119 o = newo
120 go o.RunOutputLoop()
121 continue
122 }
123 os.Exit(0)
124 }
125 }
126 }
0 /*
1 * Copyright (c) 2013-2019 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
16 package main
17
18 import (
19 "flag"
20 "fmt"
21 "log"
22 "net"
23 "os"
24 "runtime"
25 "strings"
26 "sync"
27
28 "github.com/dnstap/golang-dnstap"
29 )
30
31 type stringList []string
32
33 func (sl *stringList) Set(s string) error {
34 *sl = append(*sl, s)
35 return nil
36 }
37 func (sl *stringList) String() string {
38 return strings.Join(*sl, ", ")
39 }
40
41 var (
42 flagTimeout = flag.Duration("t", 0, "I/O timeout for tcp/ip and unix domain sockets")
43 flagWriteFile = flag.String("w", "", "write output to file")
44 flagAppendFile = flag.Bool("a", false, "append to the given file, do not overwrite. valid only when outputting a text or YAML file.")
45 flagQuietText = flag.Bool("q", false, "use quiet text output")
46 flagYamlText = flag.Bool("y", false, "use verbose YAML output")
47 flagJSONText = flag.Bool("j", false, "use verbose JSON output")
48 )
49
50 func usage() {
51 fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0])
52 flag.PrintDefaults()
53 fmt.Fprintf(os.Stderr, `
54 Quiet text output format mnemonics:
55 AQ: AUTH_QUERY
56 AR: AUTH_RESPONSE
57 RQ: RESOLVER_QUERY
58 RR: RESOLVER_RESPONSE
59 CQ: CLIENT_QUERY
60 CR: CLIENT_RESPONSE
61 FQ: FORWARDER_QUERY
62 FR: FORWARDER_RESPONSE
63 SQ: STUB_QUERY
64 SR: STUB_RESPONSE
65 TQ: TOOL_QUERY
66 TR: TOOL_RESPONSE
67 `)
68 }
69
70 func main() {
71 var tcpOutputs, unixOutputs stringList
72 var fileInputs, tcpInputs, unixInputs stringList
73
74 flag.Var(&tcpOutputs, "T", "write dnstap payloads to tcp/ip address")
75 flag.Var(&unixOutputs, "U", "write dnstap payloads to unix socket")
76 flag.Var(&fileInputs, "r", "read dnstap payloads from file")
77 flag.Var(&tcpInputs, "l", "read dnstap payloads from tcp/ip")
78 flag.Var(&unixInputs, "u", "read dnstap payloads from unix socket")
79
80 runtime.GOMAXPROCS(runtime.NumCPU())
81 log.SetFlags(0)
82 flag.Usage = usage
83
84 // Handle command-line arguments.
85 flag.Parse()
86
87 if len(fileInputs)+len(unixInputs)+len(tcpInputs) == 0 {
88 fmt.Fprintf(os.Stderr, "dnstap: Error: no inputs specified.\n")
89 os.Exit(1)
90 }
91
92 haveFormat := false
93 for _, f := range []bool{*flagQuietText, *flagYamlText, *flagJSONText} {
94 if haveFormat && f {
95 fmt.Fprintf(os.Stderr, "dnstap: Error: specify at most one of -q, -y, or -j.\n")
96 os.Exit(1)
97 }
98 haveFormat = haveFormat || f
99 }
100
101 output := newMirrorOutput()
102 if err := addSockOutputs(output, "tcp", tcpOutputs); err != nil {
103 fmt.Fprintf(os.Stderr, "dnstap: TCP error: %v\n", err)
104 os.Exit(1)
105 }
106 if err := addSockOutputs(output, "unix", unixOutputs); err != nil {
107 fmt.Fprintf(os.Stderr, "dnstap: Unix socket error: %v\n", err)
108 os.Exit(1)
109 }
110 if *flagWriteFile != "" || len(tcpOutputs)+len(unixOutputs) == 0 {
111 var format dnstap.TextFormatFunc
112
113 switch {
114 case *flagYamlText:
115 format = dnstap.YamlFormat
116 case *flagQuietText:
117 format = dnstap.TextFormat
118 case *flagJSONText:
119 format = dnstap.JSONFormat
120 }
121
122 o, err := newFileOutput(*flagWriteFile, format, *flagAppendFile)
123 if err != nil {
124 fmt.Fprintf(os.Stderr, "dnstap: File output error on '%s': %v\n",
125 *flagWriteFile, err)
126 os.Exit(1)
127 }
128 go o.RunOutputLoop()
129 output.Add(o)
130 }
131
132 go output.RunOutputLoop()
133
134 var iwg sync.WaitGroup
135 // Open the input and start the input loop.
136 for _, fname := range fileInputs {
137 i, err := dnstap.NewFrameStreamInputFromFilename(fname)
138 if err != nil {
139 fmt.Fprintf(os.Stderr, "dnstap: Failed to open input file %s: %v\n", fname, err)
140 os.Exit(1)
141 }
142 fmt.Fprintf(os.Stderr, "dnstap: opened input file %s\n", fname)
143 iwg.Add(1)
144 go runInput(i, output, &iwg)
145 }
146 for _, path := range unixInputs {
147 i, err := dnstap.NewFrameStreamSockInputFromPath(path)
148 if err != nil {
149 fmt.Fprintf(os.Stderr, "dnstap: Failed to open input socket %s: %v\n", path, err)
150 os.Exit(1)
151 }
152 i.SetTimeout(*flagTimeout)
153 fmt.Fprintf(os.Stderr, "dnstap: opened input socket %s\n", path)
154 iwg.Add(1)
155 go runInput(i, output, &iwg)
156 }
157 for _, addr := range tcpInputs {
158 l, err := net.Listen("tcp", addr)
159 if err != nil {
160 fmt.Fprintf(os.Stderr, "dnstap: Failed to listen on %s: %v\n", addr, err)
161 os.Exit(1)
162 }
163 i := dnstap.NewFrameStreamSockInput(l)
164 i.SetTimeout(*flagTimeout)
165 iwg.Add(1)
166 go runInput(i, output, &iwg)
167 }
168 iwg.Wait()
169
170 output.Close()
171 }
172
173 func runInput(i dnstap.Input, o dnstap.Output, wg *sync.WaitGroup) {
174 go i.ReadInto(o.GetOutputChannel())
175 i.Wait()
176 wg.Done()
177 }
178
179 func addSockOutputs(mo *mirrorOutput, network string, addrs stringList) error {
180 var naddr net.Addr
181 var err error
182 for _, addr := range addrs {
183 switch network {
184 case "tcp":
185 naddr, err = net.ResolveTCPAddr(network, addr)
186 case "unix":
187 naddr, err = net.ResolveUnixAddr(network, addr)
188 default:
189 return fmt.Errorf("invalid network '%s'", network)
190 }
191 if err != nil {
192 return err
193 }
194
195 o, err := dnstap.NewFrameStreamSockOutput(naddr)
196 if err != nil {
197 return err
198 }
199 o.SetTimeout(*flagTimeout)
200 go o.RunOutputLoop()
201 mo.Add(o)
202 }
203 return nil
204 }
0 /*
1 * Copyright (c) 2019 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
16 package main
17
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 select {
44 case o.GetOutputChannel() <- b:
45 default:
46 }
47 }
48 }
49 for _, o := range mo.outputs {
50 o.Close()
51 }
52 close(mo.done)
53 }
54
55 func (mo *mirrorOutput) Close() {
56 close(mo.data)
57 <-mo.done
58 }
59
60 func (mo *mirrorOutput) GetOutputChannel() chan []byte {
61 return mo.data
62 }
0 /*
1 * Copyright (c) 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
16 package dnstap
17
18 const outputChannelSize = 32
19
20 // FSContentType is the FrameStream content type for dnstap protobuf data.
21 var FSContentType = []byte("protobuf:dnstap.Dnstap")
22
23 // An Input is a source of dnstap data. It provides validation of the
24 // content type and will present any data read or received on the channel
25 // provided to the ReadInto method.
26 type Input interface {
27 ReadInto(chan []byte)
28 Wait()
29 }
30
31 // An Output is a desintaion for dnstap data. It accepts data on the channel
32 // returned from the GetOutputChannel method. The RunOutputLoop() method
33 // processes data received on this channel, and returns after the Close()
34 // method is called.
35 type Output interface {
36 GetOutputChannel() chan []byte
37 RunOutputLoop()
38 Close()
39 }
0 .deps/
1 .dirstamp
2 .libs/
3 *.pb-c.c
4 *.pb-c.h
5 *.pb.cc
6 *.pb.h
7 *.pb.go
8 *_pb2.py
9 *_pb2.pyc
0 Creative Commons Legal Code
1
2 CC0 1.0 Universal
3
4 CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
5 LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
6 ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
7 INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
8 REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
9 PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
10 THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
11 HEREUNDER.
12
13 Statement of Purpose
14
15 The laws of most jurisdictions throughout the world automatically confer
16 exclusive Copyright and Related Rights (defined below) upon the creator
17 and subsequent owner(s) (each and all, an "owner") of an original work of
18 authorship and/or a database (each, a "Work").
19
20 Certain owners wish to permanently relinquish those rights to a Work for
21 the purpose of contributing to a commons of creative, cultural and
22 scientific works ("Commons") that the public can reliably and without fear
23 of later claims of infringement build upon, modify, incorporate in other
24 works, reuse and redistribute as freely as possible in any form whatsoever
25 and for any purposes, including without limitation commercial purposes.
26 These owners may contribute to the Commons to promote the ideal of a free
27 culture and the further production of creative, cultural and scientific
28 works, or to gain reputation or greater distribution for their Work in
29 part through the use and efforts of others.
30
31 For these and/or other purposes and motivations, and without any
32 expectation of additional consideration or compensation, the person
33 associating CC0 with a Work (the "Affirmer"), to the extent that he or she
34 is an owner of Copyright and Related Rights in the Work, voluntarily
35 elects to apply CC0 to the Work and publicly distribute the Work under its
36 terms, with knowledge of his or her Copyright and Related Rights in the
37 Work and the meaning and intended legal effect of CC0 on those rights.
38
39 1. Copyright and Related Rights. A Work made available under CC0 may be
40 protected by copyright and related or neighboring rights ("Copyright and
41 Related Rights"). Copyright and Related Rights include, but are not
42 limited to, the following:
43
44 i. the right to reproduce, adapt, distribute, perform, display,
45 communicate, and translate a Work;
46 ii. moral rights retained by the original author(s) and/or performer(s);
47 iii. publicity and privacy rights pertaining to a person's image or
48 likeness depicted in a Work;
49 iv. rights protecting against unfair competition in regards to a Work,
50 subject to the limitations in paragraph 4(a), below;
51 v. rights protecting the extraction, dissemination, use and reuse of data
52 in a Work;
53 vi. database rights (such as those arising under Directive 96/9/EC of the
54 European Parliament and of the Council of 11 March 1996 on the legal
55 protection of databases, and under any national implementation
56 thereof, including any amended or successor version of such
57 directive); and
58 vii. other similar, equivalent or corresponding rights throughout the
59 world based on applicable law or treaty, and any national
60 implementations thereof.
61
62 2. Waiver. To the greatest extent permitted by, but not in contravention
63 of, applicable law, Affirmer hereby overtly, fully, permanently,
64 irrevocably and unconditionally waives, abandons, and surrenders all of
65 Affirmer's Copyright and Related Rights and associated claims and causes
66 of action, whether now known or unknown (including existing as well as
67 future claims and causes of action), in the Work (i) in all territories
68 worldwide, (ii) for the maximum duration provided by applicable law or
69 treaty (including future time extensions), (iii) in any current or future
70 medium and for any number of copies, and (iv) for any purpose whatsoever,
71 including without limitation commercial, advertising or promotional
72 purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
73 member of the public at large and to the detriment of Affirmer's heirs and
74 successors, fully intending that such Waiver shall not be subject to
75 revocation, rescission, cancellation, termination, or any other legal or
76 equitable action to disrupt the quiet enjoyment of the Work by the public
77 as contemplated by Affirmer's express Statement of Purpose.
78
79 3. Public License Fallback. Should any part of the Waiver for any reason
80 be judged legally invalid or ineffective under applicable law, then the
81 Waiver shall be preserved to the maximum extent permitted taking into
82 account Affirmer's express Statement of Purpose. In addition, to the
83 extent the Waiver is so judged Affirmer hereby grants to each affected
84 person a royalty-free, non transferable, non sublicensable, non exclusive,
85 irrevocable and unconditional license to exercise Affirmer's Copyright and
86 Related Rights in the Work (i) in all territories worldwide, (ii) for the
87 maximum duration provided by applicable law or treaty (including future
88 time extensions), (iii) in any current or future medium and for any number
89 of copies, and (iv) for any purpose whatsoever, including without
90 limitation commercial, advertising or promotional purposes (the
91 "License"). The License shall be deemed effective as of the date CC0 was
92 applied by Affirmer to the Work. Should any part of the License for any
93 reason be judged legally invalid or ineffective under applicable law, such
94 partial invalidity or ineffectiveness shall not invalidate the remainder
95 of the License, and in such case Affirmer hereby affirms that he or she
96 will not (i) exercise any of his or her remaining Copyright and Related
97 Rights in the Work or (ii) assert any associated claims and causes of
98 action with respect to the Work, in either case contrary to Affirmer's
99 express Statement of Purpose.
100
101 4. Limitations and Disclaimers.
102
103 a. No trademark or patent rights held by Affirmer are waived, abandoned,
104 surrendered, licensed or otherwise affected by this document.
105 b. Affirmer offers the Work as-is and makes no representations or
106 warranties of any kind concerning the Work, express, implied,
107 statutory or otherwise, including without limitation warranties of
108 title, merchantability, fitness for a particular purpose, non
109 infringement, or the absence of latent or other defects, accuracy, or
110 the present or absence of errors, whether or not discoverable, all to
111 the greatest extent permissible under applicable law.
112 c. Affirmer disclaims responsibility for clearing rights of other persons
113 that may apply to the Work or any use thereof, including without
114 limitation any person's Copyright and Related Rights in the Work.
115 Further, Affirmer disclaims responsibility for obtaining any necessary
116 consents, permissions or other rights required for any use of the
117 Work.
118 d. Affirmer understands and acknowledges that Creative Commons is not a
119 party to this document and has no duty or obligation with respect to
120 this CC0 or use of the Work.
0 dnstap: flexible, structured event replication format for DNS software
1 ----------------------------------------------------------------------
2
3 This directory contains only the protobuf schemas for dnstap, and is the root of
4 a repository named "dnstap.pb".
0 // dnstap: flexible, structured event replication format for DNS software
1 //
2 // This file contains the protobuf schemas for the "dnstap" structured event
3 // replication format for DNS software.
4
5 // Written in 2013-2014 by Farsight Security, Inc.
6 //
7 // To the extent possible under law, the author(s) have dedicated all
8 // copyright and related and neighboring rights to this file to the public
9 // domain worldwide. This file is distributed without any warranty.
10 //
11 // You should have received a copy of the CC0 Public Domain Dedication along
12 // with this file. If not, see:
13 //
14 // <http://creativecommons.org/publicdomain/zero/1.0/>.
15
16 package dnstap;
17
18 // "Dnstap": this is the top-level dnstap type, which is a "union" type that
19 // contains other kinds of dnstap payloads, although currently only one type
20 // of dnstap payload is defined.
21 // See: https://developers.google.com/protocol-buffers/docs/techniques#union
22 message Dnstap {
23 // DNS server identity.
24 // If enabled, this is the identity string of the DNS server which generated
25 // this message. Typically this would be the same string as returned by an
26 // "NSID" (RFC 5001) query.
27 optional bytes identity = 1;
28
29 // DNS server version.
30 // If enabled, this is the version string of the DNS server which generated
31 // this message. Typically this would be the same string as returned by a
32 // "version.bind" query.
33 optional bytes version = 2;
34
35 // Extra data for this payload.
36 // This field can be used for adding an arbitrary byte-string annotation to
37 // the payload. No encoding or interpretation is applied or enforced.
38 optional bytes extra = 3;
39
40 // Identifies which field below is filled in.
41 enum Type {
42 MESSAGE = 1;
43 }
44 required Type type = 15;
45
46 // One of the following will be filled in.
47 optional Message message = 14;
48 }
49
50 // SocketFamily: the network protocol family of a socket. This specifies how
51 // to interpret "network address" fields.
52 enum SocketFamily {
53 INET = 1; // IPv4 (RFC 791)
54 INET6 = 2; // IPv6 (RFC 2460)
55 }
56
57 // SocketProtocol: the transport protocol of a socket. This specifies how to
58 // interpret "transport port" fields.
59 enum SocketProtocol {
60 UDP = 1; // User Datagram Protocol (RFC 768)
61 TCP = 2; // Transmission Control Protocol (RFC 793)
62 }
63
64 // Message: a wire-format (RFC 1035 section 4) DNS message and associated
65 // metadata. Applications generating "Message" payloads should follow
66 // certain requirements based on the MessageType, see below.
67 message Message {
68
69 // There are eight types of "Message" defined that correspond to the
70 // four arrows in the following diagram, slightly modified from RFC 1035
71 // section 2:
72
73 // +---------+ +----------+ +--------+
74 // | | query | | query | |
75 // | Stub |-SQ--------CQ->| Recursive|-RQ----AQ->| Auth. |
76 // | Resolver| | Server | | Name |
77 // | |<-SR--------CR-| |<-RR----AR-| Server |
78 // +---------+ response | | response | |
79 // +----------+ +--------+
80
81 // Each arrow has two Type values each, one for each "end" of each arrow,
82 // because these are considered to be distinct events. Each end of each
83 // arrow on the diagram above has been marked with a two-letter Type
84 // mnemonic. Clockwise from upper left, these mnemonic values are:
85 //
86 // SQ: STUB_QUERY
87 // CQ: CLIENT_QUERY
88 // RQ: RESOLVER_QUERY
89 // AQ: AUTH_QUERY
90 // AR: AUTH_RESPONSE
91 // RR: RESOLVER_RESPONSE
92 // CR: CLIENT_RESPONSE
93 // SR: STUB_RESPONSE
94
95 // Two additional types of "Message" have been defined for the
96 // "forwarding" case where an upstream DNS server is responsible for
97 // further recursion. These are not shown on the diagram above, but have
98 // the following mnemonic values:
99
100 // FQ: FORWARDER_QUERY
101 // FR: FORWARDER_RESPONSE
102
103 // The "Message" Type values are defined below.
104
105 enum Type {
106 // AUTH_QUERY is a DNS query message received from a resolver by an
107 // authoritative name server, from the perspective of the authorative
108 // name server.
109 AUTH_QUERY = 1;
110
111 // AUTH_RESPONSE is a DNS response message sent from an authoritative
112 // name server to a resolver, from the perspective of the authoritative
113 // name server.
114 AUTH_RESPONSE = 2;
115
116 // RESOLVER_QUERY is a DNS query message sent from a resolver to an
117 // authoritative name server, from the perspective of the resolver.
118 // Resolvers typically clear the RD (recursion desired) bit when
119 // sending queries.
120 RESOLVER_QUERY = 3;
121
122 // RESOLVER_RESPONSE is a DNS response message received from an
123 // authoritative name server by a resolver, from the perspective of
124 // the resolver.
125 RESOLVER_RESPONSE = 4;
126
127 // CLIENT_QUERY is a DNS query message sent from a client to a DNS
128 // server which is expected to perform further recursion, from the
129 // perspective of the DNS server. The client may be a stub resolver or
130 // forwarder or some other type of software which typically sets the RD
131 // (recursion desired) bit when querying the DNS server. The DNS server
132 // may be a simple forwarding proxy or it may be a full recursive
133 // resolver.
134 CLIENT_QUERY = 5;
135
136 // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
137 // a client, from the perspective of the DNS server. The DNS server
138 // typically sets the RA (recursion available) bit when responding.
139 CLIENT_RESPONSE = 6;
140
141 // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
142 // server to an upstream DNS server which is expected to perform
143 // further recursion, from the perspective of the downstream DNS
144 // server.
145 FORWARDER_QUERY = 7;
146
147 // FORWARDER_RESPONSE is a DNS response message sent from an upstream
148 // DNS server performing recursion to a downstream DNS server, from the
149 // perspective of the downstream DNS server.
150 FORWARDER_RESPONSE = 8;
151
152 // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
153 // server, from the perspective of the stub resolver.
154 STUB_QUERY = 9;
155
156 // STUB_RESPONSE is a DNS response message sent from a DNS server to a
157 // stub resolver, from the perspective of the stub resolver.
158 STUB_RESPONSE = 10;
159
160 // TOOL_QUERY is a DNS query message sent from a DNS software tool to a
161 // DNS server, from the perspective of the tool.
162 TOOL_QUERY = 11;
163
164 // TOOL_RESPONSE is a DNS response message received by a DNS software
165 // tool from a DNS server, from the perspective of the tool.
166 TOOL_RESPONSE = 12;
167 }
168
169 // One of the Type values described above.
170 required Type type = 1;
171
172 // One of the SocketFamily values described above.
173 optional SocketFamily socket_family = 2;
174
175 // One of the SocketProtocol values described above.
176 optional SocketProtocol socket_protocol = 3;
177
178 // The network address of the message initiator.
179 // For SocketFamily INET, this field is 4 octets (IPv4 address).
180 // For SocketFamily INET6, this field is 16 octets (IPv6 address).
181 optional bytes query_address = 4;
182
183 // The network address of the message responder.
184 // For SocketFamily INET, this field is 4 octets (IPv4 address).
185 // For SocketFamily INET6, this field is 16 octets (IPv6 address).
186 optional bytes response_address = 5;
187
188 // The transport port of the message initiator.
189 // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
190 optional uint32 query_port = 6;
191
192 // The transport port of the message responder.
193 // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
194 optional uint32 response_port = 7;
195
196 // The time at which the DNS query message was sent or received, depending
197 // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
198 // This is the number of seconds since the UNIX epoch.
199 optional uint64 query_time_sec = 8;
200
201 // The time at which the DNS query message was sent or received.
202 // This is the seconds fraction, expressed as a count of nanoseconds.
203 optional fixed32 query_time_nsec = 9;
204
205 // The initiator's original wire-format DNS query message, verbatim.
206 optional bytes query_message = 10;
207
208 // The "zone" or "bailiwick" pertaining to the DNS query message.
209 // This is a wire-format DNS domain name.
210 optional bytes query_zone = 11;
211
212 // The time at which the DNS response message was sent or received,
213 // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
214 // CLIENT_RESPONSE.
215 // This is the number of seconds since the UNIX epoch.
216 optional uint64 response_time_sec = 12;
217
218 // The time at which the DNS response message was sent or received.
219 // This is the seconds fraction, expressed as a count of nanoseconds.
220 optional fixed32 response_time_nsec = 13;
221
222 // The responder's original wire-format DNS response message, verbatim.
223 optional bytes response_message = 14;
224 }
225
226 // All fields except for 'type' in the Message schema are optional.
227 // It is recommended that at least the following fields be filled in for
228 // particular types of Messages.
229
230 // AUTH_QUERY:
231 // socket_family, socket_protocol
232 // query_address, query_port
233 // query_message
234 // query_time_sec, query_time_nsec
235
236 // AUTH_RESPONSE:
237 // socket_family, socket_protocol
238 // query_address, query_port
239 // query_time_sec, query_time_nsec
240 // response_message
241 // response_time_sec, response_time_nsec
242
243 // RESOLVER_QUERY:
244 // socket_family, socket_protocol
245 // query_message
246 // query_time_sec, query_time_nsec
247 // query_zone
248 // response_address, response_port
249
250 // RESOLVER_RESPONSE:
251 // socket_family, socket_protocol
252 // query_time_sec, query_time_nsec
253 // query_zone
254 // response_address, response_port
255 // response_message
256 // response_time_sec, response_time_nsec
257
258 // CLIENT_QUERY:
259 // socket_family, socket_protocol
260 // query_message
261 // query_time_sec, query_time_nsec
262
263 // CLIENT_RESPONSE:
264 // socket_family, socket_protocol
265 // query_time_sec, query_time_nsec
266 // response_message
267 // response_time_sec, response_time_nsec
0 // Code generated by protoc-gen-go.
1 // source: dnstap.proto
2 // DO NOT EDIT!
3
4 /*
5 Package dnstap is a generated protocol buffer package.
6
7 It is generated from these files:
8 dnstap.proto
9
10 It has these top-level messages:
11 Dnstap
12 Message
13 */
14 package dnstap
15
16 import proto "github.com/golang/protobuf/proto"
17 import json "encoding/json"
18 import math "math"
19
20 // Reference proto, json, and math imports to suppress error if they are not otherwise used.
21 var _ = proto.Marshal
22 var _ = &json.SyntaxError{}
23 var _ = math.Inf
24
25 // SocketFamily: the network protocol family of a socket. This specifies how
26 // to interpret "network address" fields.
27 type SocketFamily int32
28
29 const (
30 SocketFamily_INET SocketFamily = 1
31 SocketFamily_INET6 SocketFamily = 2
32 )
33
34 var SocketFamily_name = map[int32]string{
35 1: "INET",
36 2: "INET6",
37 }
38 var SocketFamily_value = map[string]int32{
39 "INET": 1,
40 "INET6": 2,
41 }
42
43 func (x SocketFamily) Enum() *SocketFamily {
44 p := new(SocketFamily)
45 *p = x
46 return p
47 }
48 func (x SocketFamily) String() string {
49 return proto.EnumName(SocketFamily_name, int32(x))
50 }
51 func (x *SocketFamily) UnmarshalJSON(data []byte) error {
52 value, err := proto.UnmarshalJSONEnum(SocketFamily_value, data, "SocketFamily")
53 if err != nil {
54 return err
55 }
56 *x = SocketFamily(value)
57 return nil
58 }
59
60 // SocketProtocol: the transport protocol of a socket. This specifies how to
61 // interpret "transport port" fields.
62 type SocketProtocol int32
63
64 const (
65 SocketProtocol_UDP SocketProtocol = 1
66 SocketProtocol_TCP SocketProtocol = 2
67 )
68
69 var SocketProtocol_name = map[int32]string{
70 1: "UDP",
71 2: "TCP",
72 }
73 var SocketProtocol_value = map[string]int32{
74 "UDP": 1,
75 "TCP": 2,
76 }
77
78 func (x SocketProtocol) Enum() *SocketProtocol {
79 p := new(SocketProtocol)
80 *p = x
81 return p
82 }
83 func (x SocketProtocol) String() string {
84 return proto.EnumName(SocketProtocol_name, int32(x))
85 }
86 func (x *SocketProtocol) UnmarshalJSON(data []byte) error {
87 value, err := proto.UnmarshalJSONEnum(SocketProtocol_value, data, "SocketProtocol")
88 if err != nil {
89 return err
90 }
91 *x = SocketProtocol(value)
92 return nil
93 }
94
95 // Identifies which field below is filled in.
96 type Dnstap_Type int32
97
98 const (
99 Dnstap_MESSAGE Dnstap_Type = 1
100 )
101
102 var Dnstap_Type_name = map[int32]string{
103 1: "MESSAGE",
104 }
105 var Dnstap_Type_value = map[string]int32{
106 "MESSAGE": 1,
107 }
108
109 func (x Dnstap_Type) Enum() *Dnstap_Type {
110 p := new(Dnstap_Type)
111 *p = x
112 return p
113 }
114 func (x Dnstap_Type) String() string {
115 return proto.EnumName(Dnstap_Type_name, int32(x))
116 }
117 func (x *Dnstap_Type) UnmarshalJSON(data []byte) error {
118 value, err := proto.UnmarshalJSONEnum(Dnstap_Type_value, data, "Dnstap_Type")
119 if err != nil {
120 return err
121 }
122 *x = Dnstap_Type(value)
123 return nil
124 }
125
126 type Message_Type int32
127
128 const (
129 // AUTH_QUERY is a DNS query message received from a resolver by an
130 // authoritative name server, from the perspective of the authorative
131 // name server.
132 Message_AUTH_QUERY Message_Type = 1
133 // AUTH_RESPONSE is a DNS response message sent from an authoritative
134 // name server to a resolver, from the perspective of the authoritative
135 // name server.
136 Message_AUTH_RESPONSE Message_Type = 2
137 // RESOLVER_QUERY is a DNS query message sent from a resolver to an
138 // authoritative name server, from the perspective of the resolver.
139 // Resolvers typically clear the RD (recursion desired) bit when
140 // sending queries.
141 Message_RESOLVER_QUERY Message_Type = 3
142 // RESOLVER_RESPONSE is a DNS response message received from an
143 // authoritative name server by a resolver, from the perspective of
144 // the resolver.
145 Message_RESOLVER_RESPONSE Message_Type = 4
146 // CLIENT_QUERY is a DNS query message sent from a client to a DNS
147 // server which is expected to perform further recursion, from the
148 // perspective of the DNS server. The client may be a stub resolver or
149 // forwarder or some other type of software which typically sets the RD
150 // (recursion desired) bit when querying the DNS server. The DNS server
151 // may be a simple forwarding proxy or it may be a full recursive
152 // resolver.
153 Message_CLIENT_QUERY Message_Type = 5
154 // CLIENT_RESPONSE is a DNS response message sent from a DNS server to
155 // a client, from the perspective of the DNS server. The DNS server
156 // typically sets the RA (recursion available) bit when responding.
157 Message_CLIENT_RESPONSE Message_Type = 6
158 // FORWARDER_QUERY is a DNS query message sent from a downstream DNS
159 // server to an upstream DNS server which is expected to perform
160 // further recursion, from the perspective of the downstream DNS
161 // server.
162 Message_FORWARDER_QUERY Message_Type = 7
163 // FORWARDER_RESPONSE is a DNS response message sent from an upstream
164 // DNS server performing recursion to a downstream DNS server, from the
165 // perspective of the downstream DNS server.
166 Message_FORWARDER_RESPONSE Message_Type = 8
167 // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS
168 // server, from the perspective of the stub resolver.
169 Message_STUB_QUERY Message_Type = 9
170 // STUB_RESPONSE is a DNS response message sent from a DNS server to a
171 // stub resolver, from the perspective of the stub resolver.
172 Message_STUB_RESPONSE Message_Type = 10
173 // TOOL_QUERY is a DNS query message sent from a DNS software tool to a
174 // DNS server, from the perspective of the tool.
175 Message_TOOL_QUERY Message_Type = 11
176 // TOOL_RESPONSE is a DNS response message received by a DNS software
177 // tool from a DNS server, from the perspective of the tool.
178 Message_TOOL_RESPONSE Message_Type = 12
179 )
180
181 var Message_Type_name = map[int32]string{
182 1: "AUTH_QUERY",
183 2: "AUTH_RESPONSE",
184 3: "RESOLVER_QUERY",
185 4: "RESOLVER_RESPONSE",
186 5: "CLIENT_QUERY",
187 6: "CLIENT_RESPONSE",
188 7: "FORWARDER_QUERY",
189 8: "FORWARDER_RESPONSE",
190 9: "STUB_QUERY",
191 10: "STUB_RESPONSE",
192 11: "TOOL_QUERY",
193 12: "TOOL_RESPONSE",
194 }
195 var Message_Type_value = map[string]int32{
196 "AUTH_QUERY": 1,
197 "AUTH_RESPONSE": 2,
198 "RESOLVER_QUERY": 3,
199 "RESOLVER_RESPONSE": 4,
200 "CLIENT_QUERY": 5,
201 "CLIENT_RESPONSE": 6,
202 "FORWARDER_QUERY": 7,
203 "FORWARDER_RESPONSE": 8,
204 "STUB_QUERY": 9,
205 "STUB_RESPONSE": 10,
206 "TOOL_QUERY": 11,
207 "TOOL_RESPONSE": 12,
208 }
209
210 func (x Message_Type) Enum() *Message_Type {
211 p := new(Message_Type)
212 *p = x
213 return p
214 }
215 func (x Message_Type) String() string {
216 return proto.EnumName(Message_Type_name, int32(x))
217 }
218 func (x *Message_Type) UnmarshalJSON(data []byte) error {
219 value, err := proto.UnmarshalJSONEnum(Message_Type_value, data, "Message_Type")
220 if err != nil {
221 return err
222 }
223 *x = Message_Type(value)
224 return nil
225 }
226
227 // "Dnstap": this is the top-level dnstap type, which is a "union" type that
228 // contains other kinds of dnstap payloads, although currently only one type
229 // of dnstap payload is defined.
230 // See: https://developers.google.com/protocol-buffers/docs/techniques#union
231 type Dnstap struct {
232 // DNS server identity.
233 // If enabled, this is the identity string of the DNS server which generated
234 // this message. Typically this would be the same string as returned by an
235 // "NSID" (RFC 5001) query.
236 Identity []byte `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"`
237 // DNS server version.
238 // If enabled, this is the version string of the DNS server which generated
239 // this message. Typically this would be the same string as returned by a
240 // "version.bind" query.
241 Version []byte `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"`
242 // Extra data for this payload.
243 // This field can be used for adding an arbitrary byte-string annotation to
244 // the payload. No encoding or interpretation is applied or enforced.
245 Extra []byte `protobuf:"bytes,3,opt,name=extra" json:"extra,omitempty"`
246 Type *Dnstap_Type `protobuf:"varint,15,req,name=type,enum=dnstap.Dnstap_Type" json:"type,omitempty"`
247 // One of the following will be filled in.
248 Message *Message `protobuf:"bytes,14,opt,name=message" json:"message,omitempty"`
249 XXX_unrecognized []byte `json:"-"`
250 }
251
252 func (m *Dnstap) Reset() { *m = Dnstap{} }
253 func (m *Dnstap) String() string { return proto.CompactTextString(m) }
254 func (*Dnstap) ProtoMessage() {}
255
256 func (m *Dnstap) GetIdentity() []byte {
257 if m != nil {
258 return m.Identity
259 }
260 return nil
261 }
262
263 func (m *Dnstap) GetVersion() []byte {
264 if m != nil {
265 return m.Version
266 }
267 return nil
268 }
269
270 func (m *Dnstap) GetExtra() []byte {
271 if m != nil {
272 return m.Extra
273 }
274 return nil
275 }
276
277 func (m *Dnstap) GetType() Dnstap_Type {
278 if m != nil && m.Type != nil {
279 return *m.Type
280 }
281 return Dnstap_MESSAGE
282 }
283
284 func (m *Dnstap) GetMessage() *Message {
285 if m != nil {
286 return m.Message
287 }
288 return nil
289 }
290
291 // Message: a wire-format (RFC 1035 section 4) DNS message and associated
292 // metadata. Applications generating "Message" payloads should follow
293 // certain requirements based on the MessageType, see below.
294 type Message struct {
295 // One of the Type values described above.
296 Type *Message_Type `protobuf:"varint,1,req,name=type,enum=dnstap.Message_Type" json:"type,omitempty"`
297 // One of the SocketFamily values described above.
298 SocketFamily *SocketFamily `protobuf:"varint,2,opt,name=socket_family,enum=dnstap.SocketFamily" json:"socket_family,omitempty"`
299 // One of the SocketProtocol values described above.
300 SocketProtocol *SocketProtocol `protobuf:"varint,3,opt,name=socket_protocol,enum=dnstap.SocketProtocol" json:"socket_protocol,omitempty"`
301 // The network address of the message initiator.
302 // For SocketFamily INET, this field is 4 octets (IPv4 address).
303 // For SocketFamily INET6, this field is 16 octets (IPv6 address).
304 QueryAddress []byte `protobuf:"bytes,4,opt,name=query_address" json:"query_address,omitempty"`
305 // The network address of the message responder.
306 // For SocketFamily INET, this field is 4 octets (IPv4 address).
307 // For SocketFamily INET6, this field is 16 octets (IPv6 address).
308 ResponseAddress []byte `protobuf:"bytes,5,opt,name=response_address" json:"response_address,omitempty"`
309 // The transport port of the message initiator.
310 // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
311 QueryPort *uint32 `protobuf:"varint,6,opt,name=query_port" json:"query_port,omitempty"`
312 // The transport port of the message responder.
313 // This is a 16-bit UDP or TCP port number, depending on SocketProtocol.
314 ResponsePort *uint32 `protobuf:"varint,7,opt,name=response_port" json:"response_port,omitempty"`
315 // The time at which the DNS query message was sent or received, depending
316 // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY.
317 // This is the number of seconds since the UNIX epoch.
318 QueryTimeSec *uint64 `protobuf:"varint,8,opt,name=query_time_sec" json:"query_time_sec,omitempty"`
319 // The time at which the DNS query message was sent or received.
320 // This is the seconds fraction, expressed as a count of nanoseconds.
321 QueryTimeNsec *uint32 `protobuf:"fixed32,9,opt,name=query_time_nsec" json:"query_time_nsec,omitempty"`
322 // The initiator's original wire-format DNS query message, verbatim.
323 QueryMessage []byte `protobuf:"bytes,10,opt,name=query_message" json:"query_message,omitempty"`
324 // The "zone" or "bailiwick" pertaining to the DNS query message.
325 // This is a wire-format DNS domain name.
326 QueryZone []byte `protobuf:"bytes,11,opt,name=query_zone" json:"query_zone,omitempty"`
327 // The time at which the DNS response message was sent or received,
328 // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or
329 // CLIENT_RESPONSE.
330 // This is the number of seconds since the UNIX epoch.
331 ResponseTimeSec *uint64 `protobuf:"varint,12,opt,name=response_time_sec" json:"response_time_sec,omitempty"`
332 // The time at which the DNS response message was sent or received.
333 // This is the seconds fraction, expressed as a count of nanoseconds.
334 ResponseTimeNsec *uint32 `protobuf:"fixed32,13,opt,name=response_time_nsec" json:"response_time_nsec,omitempty"`
335 // The responder's original wire-format DNS response message, verbatim.
336 ResponseMessage []byte `protobuf:"bytes,14,opt,name=response_message" json:"response_message,omitempty"`
337 XXX_unrecognized []byte `json:"-"`
338 }
339
340 func (m *Message) Reset() { *m = Message{} }
341 func (m *Message) String() string { return proto.CompactTextString(m) }
342 func (*Message) ProtoMessage() {}
343
344 func (m *Message) GetType() Message_Type {
345 if m != nil && m.Type != nil {
346 return *m.Type
347 }
348 return Message_AUTH_QUERY
349 }
350
351 func (m *Message) GetSocketFamily() SocketFamily {
352 if m != nil && m.SocketFamily != nil {
353 return *m.SocketFamily
354 }
355 return SocketFamily_INET
356 }
357
358 func (m *Message) GetSocketProtocol() SocketProtocol {
359 if m != nil && m.SocketProtocol != nil {
360 return *m.SocketProtocol
361 }
362 return SocketProtocol_UDP
363 }
364
365 func (m *Message) GetQueryAddress() []byte {
366 if m != nil {
367 return m.QueryAddress
368 }
369 return nil
370 }
371
372 func (m *Message) GetResponseAddress() []byte {
373 if m != nil {
374 return m.ResponseAddress
375 }
376 return nil
377 }
378
379 func (m *Message) GetQueryPort() uint32 {
380 if m != nil && m.QueryPort != nil {
381 return *m.QueryPort
382 }
383 return 0
384 }
385
386 func (m *Message) GetResponsePort() uint32 {
387 if m != nil && m.ResponsePort != nil {
388 return *m.ResponsePort
389 }
390 return 0
391 }
392
393 func (m *Message) GetQueryTimeSec() uint64 {
394 if m != nil && m.QueryTimeSec != nil {
395 return *m.QueryTimeSec
396 }
397 return 0
398 }
399
400 func (m *Message) GetQueryTimeNsec() uint32 {
401 if m != nil && m.QueryTimeNsec != nil {
402 return *m.QueryTimeNsec
403 }
404 return 0
405 }
406
407 func (m *Message) GetQueryMessage() []byte {
408 if m != nil {
409 return m.QueryMessage
410 }
411 return nil
412 }
413
414 func (m *Message) GetQueryZone() []byte {
415 if m != nil {
416 return m.QueryZone
417 }
418 return nil
419 }
420
421 func (m *Message) GetResponseTimeSec() uint64 {
422 if m != nil && m.ResponseTimeSec != nil {
423 return *m.ResponseTimeSec
424 }
425 return 0
426 }
427
428 func (m *Message) GetResponseTimeNsec() uint32 {
429 if m != nil && m.ResponseTimeNsec != nil {
430 return *m.ResponseTimeNsec
431 }
432 return 0
433 }
434
435 func (m *Message) GetResponseMessage() []byte {
436 if m != nil {
437 return m.ResponseMessage
438 }
439 return nil
440 }
441
442 func init() {
443 proto.RegisterEnum("dnstap.SocketFamily", SocketFamily_name, SocketFamily_value)
444 proto.RegisterEnum("dnstap.SocketProtocol", SocketProtocol_name, SocketProtocol_value)
445 proto.RegisterEnum("dnstap.Dnstap_Type", Dnstap_Type_name, Dnstap_Type_value)
446 proto.RegisterEnum("dnstap.Message_Type", Message_Type_name, Message_Type_value)
447 }
0 package dnstap
1
2 import (
3 "fmt"
4 "net"
5 "testing"
6 "time"
7 )
8
9 func dialAndSend(t *testing.T, network, address string) *FrameStreamSockOutput {
10 var addr net.Addr
11 var err error
12 switch network {
13 case "unix":
14 addr, err = net.ResolveUnixAddr(network, address)
15 case "tcp", "tcp4", "tcp6":
16 addr, err = net.ResolveTCPAddr(network, address)
17 default:
18 err = fmt.Errorf("invalid network %s", network)
19 }
20 if err != nil {
21 t.Fatal(err)
22 }
23
24 out, err := NewFrameStreamSockOutput(addr)
25 if err != nil {
26 t.Fatal(err)
27 }
28
29 out.SetDialer(&net.Dialer{Timeout: time.Second})
30 out.SetTimeout(time.Second)
31 out.SetFlushTimeout(100 * time.Millisecond)
32 out.SetRetryInterval(time.Second)
33
34 go out.RunOutputLoop()
35 <-time.After(500 * time.Millisecond)
36 out.GetOutputChannel() <- []byte("frame")
37 return out
38 }
39
40 func readOne(t *testing.T, out chan []byte) {
41 select {
42 case <-out:
43 case <-time.After(time.Second):
44 t.Fatal("timed out waiting for frame")
45 }
46 }
47
48 // Test if dnstap can accept multiple connections on the socket
49 func TestMultiConn(t *testing.T) {
50 in, err := NewFrameStreamSockInputFromPath("dnstap.sock")
51 if err != nil {
52 t.Fatal(err)
53 }
54
55 out := make(chan []byte)
56 go in.ReadInto(out)
57
58 // send two framestream messages on different connections
59 defer dialAndSend(t, "unix", "dnstap.sock").Close()
60 defer dialAndSend(t, "unix", "dnstap.sock").Close()
61
62 readOne(t, out)
63 readOne(t, out)
64 }
65
66 func TestReconnect(t *testing.T) {
67 // Find an open port on localhost by opening a listener on an
68 // unspecified port, querying its address, then closing it.
69 l, err := net.Listen("tcp", "localhost:0")
70 if err != nil {
71 t.Fatal(err)
72 }
73 laddr := l.Addr()
74 l.Close()
75
76 defer dialAndSend(t, laddr.Network(), laddr.String()).Close()
77 defer dialAndSend(t, laddr.Network(), laddr.String()).Close()
78 time.Sleep(1500 * time.Millisecond)
79 l, err = net.Listen(laddr.Network(), laddr.String())
80 if err != nil {
81 t.Fatal(err)
82 }
83
84 in := NewFrameStreamSockInput(l)
85 out := make(chan []byte)
86 go in.ReadInto(out)
87 readOne(t, out)
88 readOne(t, out)
89 }
90
91 func BenchmarkConnectUnidirectional(b *testing.B) {
92 b.StopTimer()
93 l, err := net.Listen("tcp", "localhost:0")
94 if err != nil {
95 b.Fatal(err)
96 }
97
98 // read from tcp socket into outch
99 outch := make(chan []byte, 32)
100 go func() {
101 // wait for connection
102 s, err := l.Accept()
103 if err != nil {
104 b.Error(err)
105 close(outch)
106 return
107 }
108
109 // start rewriter
110 in, err := NewFrameStreamInput(s, false)
111 if err != nil {
112 b.Error(err)
113 close(outch)
114 return
115 }
116
117 // read ASAP into outch
118 in.ReadInto(outch)
119 close(outch)
120 }()
121
122 // read from outch exactly b.N frames
123 // this is separate from the above, because the process of rewriting tcp into outch
124 // must run in parallel with reading b.N frames from outch
125 readDone := make(chan struct{})
126 go func() {
127 // wait for the first frame before starting the timer
128 <-outch
129 i := 1
130
131 b.StartTimer()
132 for _ = range outch { i++ }
133 if i != b.N {
134 b.Error("invalid frame count")
135 }
136 close(readDone)
137 }()
138
139 // connect to tcp socket and start the output loop
140 c, err := net.Dial(l.Addr().Network(), l.Addr().String())
141 if err != nil {
142 b.Fatal(err)
143 }
144 out, err := NewFrameStreamOutput(c)
145 if err != nil {
146 b.Fatal(err)
147 }
148 go out.RunOutputLoop()
149
150 // write to the output channel exactly b.N frames
151 for i := 0; i < b.N; i++ {
152 out.GetOutputChannel() <- []byte("frame")
153 }
154 out.Close()
155
156 // wait for the reader
157 <-readDone
158 }
159
160 func BenchmarkConnectBidirectional(b *testing.B) {
161 b.StopTimer()
162 l, err := net.Listen("tcp", "localhost:0")
163 if err != nil {
164 b.Fatal(err)
165 }
166
167 // start an infinite tcp socket reader
168 in := NewFrameStreamSockInput(l)
169 outch := make(chan []byte, 32)
170 go in.ReadInto(outch)
171
172 // read up to b.N frames in background
173 readDone := make(chan struct{})
174 go func() {
175 <-outch
176 b.StartTimer()
177 for i := 1; i < b.N; i++ { <-outch } // NB: read never fails
178 close(readDone)
179 }()
180
181 // connect to tcp socket and start the output loop
182 out, err := NewFrameStreamSockOutput(l.Addr())
183 if err != nil {
184 b.Fatal(err)
185 }
186 go out.RunOutputLoop()
187
188 // write to the output channel exactly b.N frames
189 for i := 0; i < b.N; i++ {
190 out.GetOutputChannel() <- []byte("frame")
191 }
192 out.Close()
193
194 // wait for the reader
195 <-readDone
196 }