/* * Copyright (c) 2013-2014 by Farsight Security, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dnstap import ( "bytes" "fmt" "net" "strconv" "strings" "time" "github.com/miekg/dns" ) const yamlTimeFormat = "2006-01-02 15:04:05.999999999" func yamlConvertMessage(m *Message, s *bytes.Buffer) { s.WriteString(fmt.Sprint(" type: ", m.Type, "\n")) if m.QueryTimeSec != nil && m.QueryTimeNsec != nil { t := time.Unix(int64(*m.QueryTimeSec), int64(*m.QueryTimeNsec)).UTC() s.WriteString(fmt.Sprint(" query_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) } if m.ResponseTimeSec != nil && m.ResponseTimeNsec != nil { t := time.Unix(int64(*m.ResponseTimeSec), int64(*m.ResponseTimeNsec)).UTC() s.WriteString(fmt.Sprint(" response_time: !!timestamp ", t.Format(yamlTimeFormat), "\n")) } if m.SocketFamily != nil { s.WriteString(fmt.Sprint(" socket_family: ", m.SocketFamily, "\n")) } if m.SocketProtocol != nil { s.WriteString(fmt.Sprint(" socket_protocol: ", m.SocketProtocol, "\n")) } if m.QueryAddress != nil { s.WriteString(fmt.Sprint(" query_address: ", net.IP(m.QueryAddress), "\n")) } if m.ResponseAddress != nil { s.WriteString(fmt.Sprint(" response_address: ", net.IP(m.ResponseAddress), "\n")) } if m.QueryPort != nil { s.WriteString(fmt.Sprint(" query_port: ", *m.QueryPort, "\n")) } if m.ResponsePort != nil { s.WriteString(fmt.Sprint(" response_port: ", *m.ResponsePort, "\n")) } if m.QueryZone != nil { name, _, err := dns.UnpackDomainName(m.QueryZone, 0) if err != nil { fmt.Fprintf(s, " # query_zone: parse failed: %v\n", err) } else { s.WriteString(fmt.Sprint(" query_zone: ", strconv.Quote(name), "\n")) } } if m.QueryMessage != nil { msg := new(dns.Msg) err := msg.Unpack(m.QueryMessage) if err != nil { fmt.Fprintf(s, " # query_message: parse failed: %v\n", err) } else { s.WriteString(" query_message: |\n") s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") } } if m.ResponseMessage != nil { msg := new(dns.Msg) err := msg.Unpack(m.ResponseMessage) if err != nil { fmt.Fprintf(s, " # response_message: parse failed: %v\n", err) } else { s.WriteString(" response_message: |\n") s.WriteString(" " + strings.Replace(strings.TrimSpace(msg.String()), "\n", "\n ", -1) + "\n") } } s.WriteString("---\n") } // YamlFormat renders a dnstap message in YAML format. Any encapsulated DNS // messages are rendered as strings in a format similar to 'dig' output. func YamlFormat(dt *Dnstap) (out []byte, ok bool) { var s bytes.Buffer s.WriteString(fmt.Sprint("type: ", dt.Type, "\n")) if dt.Identity != nil { s.WriteString(fmt.Sprint("identity: ", strconv.Quote(string(dt.Identity)), "\n")) } if dt.Version != nil { s.WriteString(fmt.Sprint("version: ", strconv.Quote(string(dt.Version)), "\n")) } if *dt.Type == Dnstap_MESSAGE { s.WriteString("message:\n") yamlConvertMessage(dt.Message, &s) } return s.Bytes(), true }