From 13049cd5959f23856b165549229ec2a4bb73a92e Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 27 Sep 2018 14:46:11 -0700 Subject: [PATCH 01/45] start playing with dnstap within go-audit --- audit.go | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/audit.go b/audit.go index 649cb4d..ea48b03 100644 --- a/audit.go +++ b/audit.go @@ -15,6 +15,8 @@ import ( "strings" "syscall" + "github.com/dnstap/golang-dnstap" + "github.com/spf13/viper" ) @@ -307,6 +309,54 @@ func createFilters(config *viper.Viper) ([]AuditFilter, error) { return filters, nil } +func outputOpener(fname string, text, yaml bool) func() dnstap.Output { + return func() dnstap.Output { + var o dnstap.Output + var err error + if text { + o, err = dnstap.NewTextOutputFromFilename(fname, dnstap.TextFormat) + } else if yaml { + o, err = dnstap.NewTextOutputFromFilename(fname, dnstap.YamlFormat) + } else { + o, err = dnstap.NewFrameStreamOutputFromFilename(fname) + } + + if err != nil { + fmt.Fprintf(os.Stderr, "dnstap: Failed to open output file: %s\n", err) + os.Exit(1) + } + + go o.RunOutputLoop() + return o + } +} + +func outputLoop(opener func() dnstap.Output, data <-chan []byte, done chan<- struct{}) { + sigch := make(chan os.Signal, 1) + signal.Notify(sigch, os.Interrupt, syscall.SIGHUP) + o := opener() + defer func() { + o.Close() + close(done) + os.Exit(0) + }() + for { + select { + case b, ok := <-data: + if !ok { + return + } + o.GetOutputChannel() <- b + case sig := <-sigch: + if sig == syscall.SIGHUP { + o.Close() + o = opener() + continue + } + return + } + } +} func main() { configFile := flag.String("config", "", "Config file location") @@ -343,6 +393,21 @@ func main() { el.Fatal(err) } + i, err := dnstap.NewFrameStreamSockInputFromPath(config.GetString("dnstap.socket")) + if err != nil { + el.Fatal(err) + } + // Start the output loop. + output := make(chan []byte, 1) + opener := outputOpener("-", true, true) + outDone := make(chan struct{}) + go outputLoop(opener, output, outDone) + + // Start the output loop. + + i.ReadInto(output) + i.Wait() + marshaller := NewAuditMarshaller( writer, uint16(config.GetInt("events.min")), @@ -368,5 +433,6 @@ func main() { } marshaller.Consume(msg) + } } From 0777fd7ea3900f3d6a8b58504402ef5efd2737b2 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 27 Sep 2018 19:26:56 -0700 Subject: [PATCH 02/45] make this way simpler --- audit.go | 85 ++++----- dnstap/dnstap.pb.go | 448 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 482 insertions(+), 51 deletions(-) create mode 100644 dnstap/dnstap.pb.go diff --git a/audit.go b/audit.go index ea48b03..127f024 100644 --- a/audit.go +++ b/audit.go @@ -14,10 +14,13 @@ import ( "strconv" "strings" "syscall" + "github.com/spf13/viper" + "net" + fs "github.com/farsightsec/golang-framestream" + "go-audit/dnstap" + "github.com/golang/protobuf/proto" - "github.com/dnstap/golang-dnstap" - "github.com/spf13/viper" ) var l = log.New(os.Stdout, "", 0) @@ -309,54 +312,33 @@ func createFilters(config *viper.Viper) ([]AuditFilter, error) { return filters, nil } -func outputOpener(fname string, text, yaml bool) func() dnstap.Output { - return func() dnstap.Output { - var o dnstap.Output - var err error - if text { - o, err = dnstap.NewTextOutputFromFilename(fname, dnstap.TextFormat) - } else if yaml { - o, err = dnstap.NewTextOutputFromFilename(fname, dnstap.YamlFormat) - } else { - o, err = dnstap.NewFrameStreamOutputFromFilename(fname) +func dnstapRead(dnstapListener net.Listener, out chan<- string) { + for { + server, err := dnstapListener.Accept() + dec, err := fs.NewDecoder(server, &fs.DecoderOptions{ + ContentType: []byte("protobuf:dnstap.Dnstap"), + Bidirectional: true, + }) + if err != nil { + el.Fatalf("Server decoder: %s", err) + return } + frameData, err := dec.Decode() if err != nil { - fmt.Fprintf(os.Stderr, "dnstap: Failed to open output file: %s\n", err) - os.Exit(1) + el.Printf("Server decode: %s", err) } - go o.RunOutputLoop() - return o - } -} + m := &dnstap.Message{} + proto.Unmarshal(frameData, m) -func outputLoop(opener func() dnstap.Output, data <-chan []byte, done chan<- struct{}) { - sigch := make(chan os.Signal, 1) - signal.Notify(sigch, os.Interrupt, syscall.SIGHUP) - o := opener() - defer func() { - o.Close() - close(done) - os.Exit(0) - }() - for { - select { - case b, ok := <-data: - if !ok { - return - } - o.GetOutputChannel() <- b - case sig := <-sigch: - if sig == syscall.SIGHUP { - o.Close() - o = opener() - continue - } - return - } + //el.Printf(string(m.ResponseMessage)) + + out <- string(m.ResponseMessage) } + } + func main() { configFile := flag.String("config", "", "Config file location") @@ -389,24 +371,25 @@ func main() { } nlClient, err := NewNetlinkClient(config.GetInt("socket_buffer.receive")) + if err != nil { el.Fatal(err) } + dnstapSock := config.GetString("dnstap.socket") + el.Println("dnstap.socket path: ", dnstapSock) - i, err := dnstap.NewFrameStreamSockInputFromPath(config.GetString("dnstap.socket")) + os.Remove(dnstapSock) + + dnstapListener, err := net.Listen("unix", dnstapSock) if err != nil { el.Fatal(err) } - // Start the output loop. - output := make(chan []byte, 1) - opener := outputOpener("-", true, true) - outDone := make(chan struct{}) - go outputLoop(opener, output, outDone) - // Start the output loop. + out := make(chan string) + + go dnstapRead(dnstapListener, out) - i.ReadInto(output) - i.Wait() + fmt.Println(<-out) marshaller := NewAuditMarshaller( writer, diff --git a/dnstap/dnstap.pb.go b/dnstap/dnstap.pb.go new file mode 100644 index 0000000..43b5fd1 --- /dev/null +++ b/dnstap/dnstap.pb.go @@ -0,0 +1,448 @@ +// Code generated by protoc-gen-go. +// source: dnstap.proto +// DO NOT EDIT! + +/* +Package dnstap is a generated protocol buffer package. + +It is generated from these files: + dnstap.proto + +It has these top-level messages: + Dnstap + Message +*/ +package dnstap + +import proto "github.com/golang/protobuf/proto" +import json "encoding/json" +import math "math" + +// Reference proto, json, and math imports to suppress error if they are not otherwise used. +var _ = proto.Marshal +var _ = &json.SyntaxError{} +var _ = math.Inf + +// SocketFamily: the network protocol family of a socket. This specifies how +// to interpret "network address" fields. +type SocketFamily int32 + +const ( + SocketFamily_INET SocketFamily = 1 + SocketFamily_INET6 SocketFamily = 2 +) + +var SocketFamily_name = map[int32]string{ + 1: "INET", + 2: "INET6", +} +var SocketFamily_value = map[string]int32{ + "INET": 1, + "INET6": 2, +} + +func (x SocketFamily) Enum() *SocketFamily { + p := new(SocketFamily) + *p = x + return p +} +func (x SocketFamily) String() string { + return proto.EnumName(SocketFamily_name, int32(x)) +} +func (x *SocketFamily) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(SocketFamily_value, data, "SocketFamily") + if err != nil { + return err + } + *x = SocketFamily(value) + return nil +} + +// SocketProtocol: the transport protocol of a socket. This specifies how to +// interpret "transport port" fields. +type SocketProtocol int32 + +const ( + SocketProtocol_UDP SocketProtocol = 1 + SocketProtocol_TCP SocketProtocol = 2 +) + +var SocketProtocol_name = map[int32]string{ + 1: "UDP", + 2: "TCP", +} +var SocketProtocol_value = map[string]int32{ + "UDP": 1, + "TCP": 2, +} + +func (x SocketProtocol) Enum() *SocketProtocol { + p := new(SocketProtocol) + *p = x + return p +} +func (x SocketProtocol) String() string { + return proto.EnumName(SocketProtocol_name, int32(x)) +} +func (x *SocketProtocol) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(SocketProtocol_value, data, "SocketProtocol") + if err != nil { + return err + } + *x = SocketProtocol(value) + return nil +} + +// Identifies which field below is filled in. +type Dnstap_Type int32 + +const ( + Dnstap_MESSAGE Dnstap_Type = 1 +) + +var Dnstap_Type_name = map[int32]string{ + 1: "MESSAGE", +} +var Dnstap_Type_value = map[string]int32{ + "MESSAGE": 1, +} + +func (x Dnstap_Type) Enum() *Dnstap_Type { + p := new(Dnstap_Type) + *p = x + return p +} +func (x Dnstap_Type) String() string { + return proto.EnumName(Dnstap_Type_name, int32(x)) +} +func (x *Dnstap_Type) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Dnstap_Type_value, data, "Dnstap_Type") + if err != nil { + return err + } + *x = Dnstap_Type(value) + return nil +} + +type Message_Type int32 + +const ( + // AUTH_QUERY is a DNS query message received from a resolver by an + // authoritative name server, from the perspective of the authorative + // name server. + Message_AUTH_QUERY Message_Type = 1 + // AUTH_RESPONSE is a DNS response message sent from an authoritative + // name server to a resolver, from the perspective of the authoritative + // name server. + Message_AUTH_RESPONSE Message_Type = 2 + // RESOLVER_QUERY is a DNS query message sent from a resolver to an + // authoritative name server, from the perspective of the resolver. + // Resolvers typically clear the RD (recursion desired) bit when + // sending queries. + Message_RESOLVER_QUERY Message_Type = 3 + // RESOLVER_RESPONSE is a DNS response message received from an + // authoritative name server by a resolver, from the perspective of + // the resolver. + Message_RESOLVER_RESPONSE Message_Type = 4 + // CLIENT_QUERY is a DNS query message sent from a client to a DNS + // server which is expected to perform further recursion, from the + // perspective of the DNS server. The client may be a stub resolver or + // forwarder or some other type of software which typically sets the RD + // (recursion desired) bit when querying the DNS server. The DNS server + // may be a simple forwarding proxy or it may be a full recursive + // resolver. + Message_CLIENT_QUERY Message_Type = 5 + // CLIENT_RESPONSE is a DNS response message sent from a DNS server to + // a client, from the perspective of the DNS server. The DNS server + // typically sets the RA (recursion available) bit when responding. + Message_CLIENT_RESPONSE Message_Type = 6 + // FORWARDER_QUERY is a DNS query message sent from a downstream DNS + // server to an upstream DNS server which is expected to perform + // further recursion, from the perspective of the downstream DNS + // server. + Message_FORWARDER_QUERY Message_Type = 7 + // FORWARDER_RESPONSE is a DNS response message sent from an upstream + // DNS server performing recursion to a downstream DNS server, from the + // perspective of the downstream DNS server. + Message_FORWARDER_RESPONSE Message_Type = 8 + // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS + // server, from the perspective of the stub resolver. + Message_STUB_QUERY Message_Type = 9 + // STUB_RESPONSE is a DNS response message sent from a DNS server to a + // stub resolver, from the perspective of the stub resolver. + Message_STUB_RESPONSE Message_Type = 10 + // TOOL_QUERY is a DNS query message sent from a DNS software tool to a + // DNS server, from the perspective of the tool. + Message_TOOL_QUERY Message_Type = 11 + // TOOL_RESPONSE is a DNS response message received by a DNS software + // tool from a DNS server, from the perspective of the tool. + Message_TOOL_RESPONSE Message_Type = 12 +) + +var Message_Type_name = map[int32]string{ + 1: "AUTH_QUERY", + 2: "AUTH_RESPONSE", + 3: "RESOLVER_QUERY", + 4: "RESOLVER_RESPONSE", + 5: "CLIENT_QUERY", + 6: "CLIENT_RESPONSE", + 7: "FORWARDER_QUERY", + 8: "FORWARDER_RESPONSE", + 9: "STUB_QUERY", + 10: "STUB_RESPONSE", + 11: "TOOL_QUERY", + 12: "TOOL_RESPONSE", +} +var Message_Type_value = map[string]int32{ + "AUTH_QUERY": 1, + "AUTH_RESPONSE": 2, + "RESOLVER_QUERY": 3, + "RESOLVER_RESPONSE": 4, + "CLIENT_QUERY": 5, + "CLIENT_RESPONSE": 6, + "FORWARDER_QUERY": 7, + "FORWARDER_RESPONSE": 8, + "STUB_QUERY": 9, + "STUB_RESPONSE": 10, + "TOOL_QUERY": 11, + "TOOL_RESPONSE": 12, +} + +func (x Message_Type) Enum() *Message_Type { + p := new(Message_Type) + *p = x + return p +} +func (x Message_Type) String() string { + return proto.EnumName(Message_Type_name, int32(x)) +} +func (x *Message_Type) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(Message_Type_value, data, "Message_Type") + if err != nil { + return err + } + *x = Message_Type(value) + return nil +} + +// "Dnstap": this is the top-level dnstap type, which is a "union" type that +// contains other kinds of dnstap payloads, although currently only one type +// of dnstap payload is defined. +// See: https://developers.google.com/protocol-buffers/docs/techniques#union +type Dnstap struct { + // DNS server identity. + // If enabled, this is the identity string of the DNS server which generated + // this message. Typically this would be the same string as returned by an + // "NSID" (RFC 5001) query. + Identity []byte `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` + // DNS server version. + // If enabled, this is the version string of the DNS server which generated + // this message. Typically this would be the same string as returned by a + // "version.bind" query. + Version []byte `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` + // Extra data for this payload. + // This field can be used for adding an arbitrary byte-string annotation to + // the payload. No encoding or interpretation is applied or enforced. + Extra []byte `protobuf:"bytes,3,opt,name=extra" json:"extra,omitempty"` + Type *Dnstap_Type `protobuf:"varint,15,req,name=type,enum=dnstap.Dnstap_Type" json:"type,omitempty"` + // One of the following will be filled in. + Message *Message `protobuf:"bytes,14,opt,name=message" json:"message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Dnstap) Reset() { *m = Dnstap{} } +func (m *Dnstap) String() string { return proto.CompactTextString(m) } +func (*Dnstap) ProtoMessage() {} + +func (m *Dnstap) GetIdentity() []byte { + if m != nil { + return m.Identity + } + return nil +} + +func (m *Dnstap) GetVersion() []byte { + if m != nil { + return m.Version + } + return nil +} + +func (m *Dnstap) GetExtra() []byte { + if m != nil { + return m.Extra + } + return nil +} + +func (m *Dnstap) GetType() Dnstap_Type { + if m != nil && m.Type != nil { + return *m.Type + } + return Dnstap_MESSAGE +} + +func (m *Dnstap) GetMessage() *Message { + if m != nil { + return m.Message + } + return nil +} + +// Message: a wire-format (RFC 1035 section 4) DNS message and associated +// metadata. Applications generating "Message" payloads should follow +// certain requirements based on the MessageType, see below. +type Message struct { + // One of the Type values described above. + Type *Message_Type `protobuf:"varint,1,req,name=type,enum=dnstap.Message_Type" json:"type,omitempty"` + // One of the SocketFamily values described above. + SocketFamily *SocketFamily `protobuf:"varint,2,opt,name=socket_family,enum=dnstap.SocketFamily" json:"socket_family,omitempty"` + // One of the SocketProtocol values described above. + SocketProtocol *SocketProtocol `protobuf:"varint,3,opt,name=socket_protocol,enum=dnstap.SocketProtocol" json:"socket_protocol,omitempty"` + // The network address of the message initiator. + // For SocketFamily INET, this field is 4 octets (IPv4 address). + // For SocketFamily INET6, this field is 16 octets (IPv6 address). + QueryAddress []byte `protobuf:"bytes,4,opt,name=query_address" json:"query_address,omitempty"` + // The network address of the message responder. + // For SocketFamily INET, this field is 4 octets (IPv4 address). + // For SocketFamily INET6, this field is 16 octets (IPv6 address). + ResponseAddress []byte `protobuf:"bytes,5,opt,name=response_address" json:"response_address,omitempty"` + // The transport port of the message initiator. + // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. + QueryPort *uint32 `protobuf:"varint,6,opt,name=query_port" json:"query_port,omitempty"` + // The transport port of the message responder. + // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. + ResponsePort *uint32 `protobuf:"varint,7,opt,name=response_port" json:"response_port,omitempty"` + // The time at which the DNS query message was sent or received, depending + // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. + // This is the number of seconds since the UNIX epoch. + QueryTimeSec *uint64 `protobuf:"varint,8,opt,name=query_time_sec" json:"query_time_sec,omitempty"` + // The time at which the DNS query message was sent or received. + // This is the seconds fraction, expressed as a count of nanoseconds. + QueryTimeNsec *uint32 `protobuf:"fixed32,9,opt,name=query_time_nsec" json:"query_time_nsec,omitempty"` + // The initiator's original wire-format DNS query message, verbatim. + QueryMessage []byte `protobuf:"bytes,10,opt,name=query_message" json:"query_message,omitempty"` + // The "zone" or "bailiwick" pertaining to the DNS query message. + // This is a wire-format DNS domain name. + QueryZone []byte `protobuf:"bytes,11,opt,name=query_zone" json:"query_zone,omitempty"` + // The time at which the DNS response message was sent or received, + // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or + // CLIENT_RESPONSE. + // This is the number of seconds since the UNIX epoch. + ResponseTimeSec *uint64 `protobuf:"varint,12,opt,name=response_time_sec" json:"response_time_sec,omitempty"` + // The time at which the DNS response message was sent or received. + // This is the seconds fraction, expressed as a count of nanoseconds. + ResponseTimeNsec *uint32 `protobuf:"fixed32,13,opt,name=response_time_nsec" json:"response_time_nsec,omitempty"` + // The responder's original wire-format DNS response message, verbatim. + ResponseMessage []byte `protobuf:"bytes,14,opt,name=response_message" json:"response_message,omitempty"` + XXX_unrecognized []byte `json:"-"` +} + +func (m *Message) Reset() { *m = Message{} } +func (m *Message) String() string { return proto.CompactTextString(m) } +func (*Message) ProtoMessage() {} + +func (m *Message) GetType() Message_Type { + if m != nil && m.Type != nil { + return *m.Type + } + return Message_AUTH_QUERY +} + +func (m *Message) GetSocketFamily() SocketFamily { + if m != nil && m.SocketFamily != nil { + return *m.SocketFamily + } + return SocketFamily_INET +} + +func (m *Message) GetSocketProtocol() SocketProtocol { + if m != nil && m.SocketProtocol != nil { + return *m.SocketProtocol + } + return SocketProtocol_UDP +} + +func (m *Message) GetQueryAddress() []byte { + if m != nil { + return m.QueryAddress + } + return nil +} + +func (m *Message) GetResponseAddress() []byte { + if m != nil { + return m.ResponseAddress + } + return nil +} + +func (m *Message) GetQueryPort() uint32 { + if m != nil && m.QueryPort != nil { + return *m.QueryPort + } + return 0 +} + +func (m *Message) GetResponsePort() uint32 { + if m != nil && m.ResponsePort != nil { + return *m.ResponsePort + } + return 0 +} + +func (m *Message) GetQueryTimeSec() uint64 { + if m != nil && m.QueryTimeSec != nil { + return *m.QueryTimeSec + } + return 0 +} + +func (m *Message) GetQueryTimeNsec() uint32 { + if m != nil && m.QueryTimeNsec != nil { + return *m.QueryTimeNsec + } + return 0 +} + +func (m *Message) GetQueryMessage() []byte { + if m != nil { + return m.QueryMessage + } + return nil +} + +func (m *Message) GetQueryZone() []byte { + if m != nil { + return m.QueryZone + } + return nil +} + +func (m *Message) GetResponseTimeSec() uint64 { + if m != nil && m.ResponseTimeSec != nil { + return *m.ResponseTimeSec + } + return 0 +} + +func (m *Message) GetResponseTimeNsec() uint32 { + if m != nil && m.ResponseTimeNsec != nil { + return *m.ResponseTimeNsec + } + return 0 +} + +func (m *Message) GetResponseMessage() []byte { + if m != nil { + return m.ResponseMessage + } + return nil +} + +func init() { + proto.RegisterEnum("dnstap.SocketFamily", SocketFamily_name, SocketFamily_value) + proto.RegisterEnum("dnstap.SocketProtocol", SocketProtocol_name, SocketProtocol_value) + proto.RegisterEnum("dnstap.Dnstap_Type", Dnstap_Type_name, Dnstap_Type_value) + proto.RegisterEnum("dnstap.Message_Type", Message_Type_name, Message_Type_value) +} From 2d6f70a32f57645925f5e6723600f794cca9fb22 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 27 Sep 2018 20:17:51 -0700 Subject: [PATCH 03/45] wip --- audit.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/audit.go b/audit.go index 127f024..52d94ff 100644 --- a/audit.go +++ b/audit.go @@ -329,12 +329,11 @@ func dnstapRead(dnstapListener net.Listener, out chan<- string) { el.Printf("Server decode: %s", err) } - m := &dnstap.Message{} + m := &dnstap.Dnstap{} proto.Unmarshal(frameData, m) - //el.Printf(string(m.ResponseMessage)) - out <- string(m.ResponseMessage) + out <- m.Message.String() } } From abcee0c3a795a0c43dcbc3a4686b578ae3013e7b Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 28 Sep 2018 15:08:18 -0700 Subject: [PATCH 04/45] get message response ip and name --- audit.go | 55 ++++++++++------------------ dnstap_cache.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 37 deletions(-) create mode 100644 dnstap_cache.go diff --git a/audit.go b/audit.go index 52d94ff..7ed782c 100644 --- a/audit.go +++ b/audit.go @@ -15,11 +15,7 @@ import ( "strings" "syscall" "github.com/spf13/viper" - "net" - fs "github.com/farsightsec/golang-framestream" - "go-audit/dnstap" - "github.com/golang/protobuf/proto" - + "github.com/dnstap/golang-dnstap" ) @@ -81,6 +77,7 @@ func setRules(config *viper.Viper, e executor) error { } } else { return errors.New("No audit rules found") + return errors.New("No audit rules found") } return nil @@ -312,31 +309,6 @@ func createFilters(config *viper.Viper) ([]AuditFilter, error) { return filters, nil } -func dnstapRead(dnstapListener net.Listener, out chan<- string) { - for { - server, err := dnstapListener.Accept() - dec, err := fs.NewDecoder(server, &fs.DecoderOptions{ - ContentType: []byte("protobuf:dnstap.Dnstap"), - Bidirectional: true, - }) - if err != nil { - el.Fatalf("Server decoder: %s", err) - return - } - frameData, err := dec.Decode() - - if err != nil { - el.Printf("Server decode: %s", err) - } - - m := &dnstap.Dnstap{} - proto.Unmarshal(frameData, m) - - - out <- m.Message.String() - } - -} func main() { configFile := flag.String("config", "", "Config file location") @@ -375,20 +347,29 @@ func main() { el.Fatal(err) } dnstapSock := config.GetString("dnstap.socket") - el.Println("dnstap.socket path: ", dnstapSock) - os.Remove(dnstapSock) + var i dnstap.Input + + // Start the output loop. + output := make(chan []byte, 1) + opener := outputOpener() + outDone := make(chan struct{}) + go outputLoop(opener, output, outDone) - dnstapListener, err := net.Listen("unix", dnstapSock) + i, err = dnstap.NewFrameStreamSockInputFromPath(dnstapSock) if err != nil { - el.Fatal(err) + fmt.Fprintf(os.Stderr, "dnstap: Failed to open input socket: %s\n", err) + os.Exit(1) } + fmt.Fprintf(os.Stderr, "dnstap: opened input socket %s\n", dnstapSock) - out := make(chan string) + i.ReadInto(output) - go dnstapRead(dnstapListener, out) + // Wait for input loop to finish. + i.Wait() + close(output) - fmt.Println(<-out) + <-outDone marshaller := NewAuditMarshaller( writer, diff --git a/dnstap_cache.go b/dnstap_cache.go new file mode 100644 index 0000000..3af7065 --- /dev/null +++ b/dnstap_cache.go @@ -0,0 +1,95 @@ +package main + +import ( + "github.com/golang/protobuf/proto" + "os/signal" + "os" + "syscall" + "github.com/dnstap/golang-dnstap" + "github.com/miekg/dns" +) + +const outputChannelSize = 32 + +type DnsOutput struct { + outputChannel chan []byte + wait chan bool +} + +func NewDnsOutput() (o *DnsOutput) { + o = new(DnsOutput) + o.outputChannel = make(chan []byte, outputChannelSize) + o.wait = make(chan bool) + return +} + +func (o *DnsOutput) GetOutputChannel() chan []byte { + return o.outputChannel +} + +func (o *DnsOutput) RunOutputLoop() { + dt := &dnstap.Dnstap{} + for frame := range o.outputChannel { + if err := proto.Unmarshal(frame, dt); err != nil { + el.Fatalf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) + break + } + if *dt.Type == dnstap.Dnstap_MESSAGE { + if dt.Message.ResponseMessage != nil { + msg := new(dns.Msg) + err := msg.Unpack(dt.Message.ResponseMessage) + if err != nil { + el.Println(err) + } else { + for i, rr := range msg.Answer { + if msg.Answer[i].Header().Rrtype == dns.TypeA { + el.Println(i, msg.Answer[i].(*dns.A).A.String(), rr.Header().Name) + } + } + } + } + } + } + close(o.wait) +} + +func (o *DnsOutput) Close() { + close(o.outputChannel) + <-o.wait +} + +func outputOpener() func() dnstap.Output { + return func() dnstap.Output { + var o dnstap.Output + o = NewDnsOutput() + go o.RunOutputLoop() + return o + } +} + +func outputLoop(opener func() dnstap.Output, data <-chan []byte, done chan<- struct{}) { + sigch := make(chan os.Signal, 1) + signal.Notify(sigch, os.Interrupt, syscall.SIGHUP) + o := opener() + defer func() { + o.Close() + close(done) + os.Exit(0) + }() + for { + select { + case b, ok := <-data: + if !ok { + return + } + o.GetOutputChannel() <- b + case sig := <-sigch: + if sig == syscall.SIGHUP { + o.Close() + o = opener() + continue + } + return + } + } +} From 9598dec0d5d90ae0ff936733be7b17945f39b880 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 28 Sep 2018 15:33:56 -0700 Subject: [PATCH 05/45] add a simple cache --- audit.go | 6 ++---- client.go | 2 +- dnstap_cache.go | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/audit.go b/audit.go index 7ed782c..74b350e 100644 --- a/audit.go +++ b/audit.go @@ -4,6 +4,8 @@ import ( "errors" "flag" "fmt" + "github.com/dnstap/golang-dnstap" + "github.com/spf13/viper" "log" "log/syslog" "os" @@ -14,9 +16,6 @@ import ( "strconv" "strings" "syscall" - "github.com/spf13/viper" - "github.com/dnstap/golang-dnstap" - ) var l = log.New(os.Stdout, "", 0) @@ -309,7 +308,6 @@ func createFilters(config *viper.Viper) ([]AuditFilter, error) { return filters, nil } - func main() { configFile := flag.String("config", "", "Config file location") diff --git a/client.go b/client.go index 7538cb1..67a606d 100644 --- a/client.go +++ b/client.go @@ -4,10 +4,10 @@ import ( "bytes" "encoding/binary" "errors" + "fmt" "sync/atomic" "syscall" "time" - "fmt" ) // Endianness is an alias for what we assume is the current machine endianness diff --git a/dnstap_cache.go b/dnstap_cache.go index 3af7065..711dac1 100644 --- a/dnstap_cache.go +++ b/dnstap_cache.go @@ -1,15 +1,20 @@ package main import ( + "github.com/dnstap/golang-dnstap" "github.com/golang/protobuf/proto" - "os/signal" + "github.com/miekg/dns" + "github.com/patrickmn/go-cache" "os" + "os/signal" "syscall" - "github.com/dnstap/golang-dnstap" - "github.com/miekg/dns" + "time" ) const outputChannelSize = 32 +const defaulTimeout = 24 * time.Hour + +var c = cache.New(defaulTimeout, defaulTimeout*2) type DnsOutput struct { outputChannel chan []byte @@ -43,7 +48,11 @@ func (o *DnsOutput) RunOutputLoop() { } else { for i, rr := range msg.Answer { if msg.Answer[i].Header().Rrtype == dns.TypeA { - el.Println(i, msg.Answer[i].(*dns.A).A.String(), rr.Header().Name) + ipAddr := msg.Answer[i].(*dns.A).A.String() + hostname := rr.Header().Name + c.Set(ipAddr, hostname, defaulTimeout) + el.Println(c.Items()) + // el.Println(i, msg.Answer[i].(*dns.A).A.String(), rr.Header().Name) } } } From 86b6f046549189caa133198724a46b584f4262ad Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 28 Sep 2018 15:51:47 -0700 Subject: [PATCH 06/45] remove duplicate return --- audit.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/audit.go b/audit.go index 74b350e..fdd8ecd 100644 --- a/audit.go +++ b/audit.go @@ -76,7 +76,6 @@ func setRules(config *viper.Viper, e executor) error { } } else { return errors.New("No audit rules found") - return errors.New("No audit rules found") } return nil @@ -367,7 +366,7 @@ func main() { i.Wait() close(output) - <-outDone + // <-outDone marshaller := NewAuditMarshaller( writer, From dbaa55cc75382b31568807d5065b034ad0a2b440 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 28 Sep 2018 16:07:35 -0700 Subject: [PATCH 07/45] make go-audit run again --- audit.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/audit.go b/audit.go index fdd8ecd..758a9cf 100644 --- a/audit.go +++ b/audit.go @@ -360,13 +360,7 @@ func main() { } fmt.Fprintf(os.Stderr, "dnstap: opened input socket %s\n", dnstapSock) - i.ReadInto(output) - - // Wait for input loop to finish. - i.Wait() - close(output) - - // <-outDone + go i.ReadInto(output) marshaller := NewAuditMarshaller( writer, From 32b986abec03df34ce0bea5b89b6f0c29a2d2d11 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Sat, 29 Sep 2018 22:18:56 -0700 Subject: [PATCH 08/45] add dns map --- parser.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/parser.go b/parser.go index 84ba6fe..5811b44 100644 --- a/parser.go +++ b/parser.go @@ -2,6 +2,8 @@ package main import ( "bytes" + "encoding/hex" + "fmt" "os/user" "strconv" "strings" @@ -10,6 +12,7 @@ import ( ) var uidMap = map[string]string{} +var DNSMap = map[string]string{} var headerEndChar = []byte{")"[0]} var headerSepChar = byte(':') var spaceChar = byte(' ') @@ -33,6 +36,7 @@ type AuditMessageGroup struct { CompleteAfter time.Time `json:"-"` Msgs []*AuditMessage `json:"messages"` UidMap map[string]string `json:"uid_map"` + DNSMap map[string]string `json:"dns_map"` Syscall string `json:"-"` } @@ -44,6 +48,7 @@ func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup { AuditTime: am.AuditTime, CompleteAfter: time.Now().Add(COMPLETE_AFTER), UidMap: make(map[string]string, 2), // Usually only 2 individual uids per execve + DNSMap: make(map[string]string, 2), // Usually only 2 individual uids per execve Msgs: make([]*AuditMessage, 0, 6), } @@ -90,6 +95,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { case 1309, 1307, 1306: + amg.mapDNS(am) // Don't map uids here case 1300: amg.findSyscall(am) @@ -99,6 +105,54 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { } } +// Find all `saddr=` occurrences in a message and map to dnstap cache +func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { + data := am.Data + start := 0 + end := 0 + + for { + if start = strings.Index(data, "saddr="); start < 0 { + break + } + + // Progress the start point beyon the = sign + start += 6 + if end = strings.IndexByte(data[start:], spaceChar); end < 0 { + // There was no ending space, maybe the uid is at the end of the line + end = len(data) - start + + // If the end of the line is greater than 5 characters away (overflows a 16 bit uint) then it can't be a uid + if end > 34 { + break + } + } + + saddr := data[start : start+end] + // todo: check the socket family and if its ipv4 + ipv4Hex := saddr[8:16] + octet, _ := hex.DecodeString(ipv4Hex) + ipAddr := fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) + + // Don't bother re-adding if the existing group already has the mapping + if _, ok := amg.DNSMap[ipAddr]; !ok { + DNSHost, ok := c.Get(ipAddr) + if ok { + amg.DNSMap[ipAddr] = DNSHost.(string) + } + } + + // Find the next uid= if we have space for one + next := start + end + 1 + if next >= len(data) { + break + } + + data = data[next:] + } + +} + // Find all `uid=` occurrences in a message and adds the username to the UidMap object func (amg *AuditMessageGroup) mapUids(am *AuditMessage) { data := am.Data From 403172f043e47d13d320d9521c8ff887c57c8a82 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 1 Oct 2018 08:44:24 -0700 Subject: [PATCH 09/45] wip and now working --- audit.go | 18 ++------ dnstap.go | 93 +++++++++++++++++++++++++++++++++++++ dnstap_cache.go | 104 ------------------------------------------ go-audit.yaml.example | 4 ++ parser.go | 1 - 5 files changed, 100 insertions(+), 120 deletions(-) create mode 100644 dnstap.go delete mode 100644 dnstap_cache.go diff --git a/audit.go b/audit.go index 758a9cf..ec9549d 100644 --- a/audit.go +++ b/audit.go @@ -4,7 +4,6 @@ import ( "errors" "flag" "fmt" - "github.com/dnstap/golang-dnstap" "github.com/spf13/viper" "log" "log/syslog" @@ -343,24 +342,13 @@ func main() { if err != nil { el.Fatal(err) } - dnstapSock := config.GetString("dnstap.socket") - var i dnstap.Input - - // Start the output loop. - output := make(chan []byte, 1) - opener := outputOpener() - outDone := make(chan struct{}) - go outputLoop(opener, output, outDone) - - i, err = dnstap.NewFrameStreamSockInputFromPath(dnstapSock) + dnstapClient, err := NewDNSTap(config.GetString("dnstap.socket")) if err != nil { - fmt.Fprintf(os.Stderr, "dnstap: Failed to open input socket: %s\n", err) - os.Exit(1) + el.Fatal(err) } - fmt.Fprintf(os.Stderr, "dnstap: opened input socket %s\n", dnstapSock) - go i.ReadInto(output) + go dnstapClient.readSock() marshaller := NewAuditMarshaller( writer, diff --git a/dnstap.go b/dnstap.go new file mode 100644 index 0000000..451a040 --- /dev/null +++ b/dnstap.go @@ -0,0 +1,93 @@ +package main + +import ( + "net" + "os" + "time" + + "github.com/dnstap/golang-dnstap" + "github.com/farsightsec/golang-framestream" + "github.com/golang/protobuf/proto" + "github.com/miekg/dns" + "github.com/patrickmn/go-cache" +) + +const defaulTimeout = 24 * time.Hour + +var c = cache.New(defaulTimeout, defaulTimeout*2) + +type DNSTap struct { + Listener net.Listener + //Cache *cache.Cache +} + +func NewDNSTap(socketPath string) (*DNSTap, error) { + os.Remove(socketPath) + //c := cache.New(defaulTimeout, defaulTimeout *2) + l, err := net.Listen("unix", socketPath) + if err != nil { + el.Fatal("Listen error: ", err) + return nil, err + } + d := &DNSTap{ + Listener: l, + //Cache: c, + } + return d, nil +} + +func (d *DNSTap) readSock() { + for { + conn, err := d.Listener.Accept() + if err != nil { + el.Printf("net.Listener.Accept() failed: %s\n", err) + continue + } + go d.frameDecode(conn) + } +} + +func (d *DNSTap) frameDecode(conn net.Conn) { + decoderOptions := &framestream.DecoderOptions{ + ContentType: []byte("protobuf:dnstap.Dnstap"), + Bidirectional: true, + } + dec, err := framestream.NewDecoder(conn, decoderOptions) + if err != nil { + el.Printf("framestream.NewDecoder failed: %s\n", err) + } + for { + frame, err := dec.Decode() + if err != nil { + el.Fatalf("framestream.Decoder.Decode() failed: %s\n", err) + break + } + dt := &dnstap.Dnstap{} + if err := proto.Unmarshal(frame, dt); err != nil { + el.Fatalf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) + break + } + if *dt.Type == dnstap.Dnstap_MESSAGE { + msg := new(dns.Msg) + if dt.Message.ResponseMessage != nil { + err := msg.Unpack(dt.Message.ResponseMessage) + if err != nil { + el.Fatalf("msg.Unpack:() failed: %s \n", err) + } else { + d.storeDNSRec(msg) + } + } + } + } +} + +func (d *DNSTap) storeDNSRec(msg *dns.Msg) { + for i, rr := range msg.Answer { + if msg.Answer[i].Header().Rrtype == dns.TypeA { + ipAddr := msg.Answer[i].(*dns.A).A.String() + hostname := rr.Header().Name + c.Set(ipAddr, hostname, defaulTimeout) + } + + } +} diff --git a/dnstap_cache.go b/dnstap_cache.go deleted file mode 100644 index 711dac1..0000000 --- a/dnstap_cache.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -import ( - "github.com/dnstap/golang-dnstap" - "github.com/golang/protobuf/proto" - "github.com/miekg/dns" - "github.com/patrickmn/go-cache" - "os" - "os/signal" - "syscall" - "time" -) - -const outputChannelSize = 32 -const defaulTimeout = 24 * time.Hour - -var c = cache.New(defaulTimeout, defaulTimeout*2) - -type DnsOutput struct { - outputChannel chan []byte - wait chan bool -} - -func NewDnsOutput() (o *DnsOutput) { - o = new(DnsOutput) - o.outputChannel = make(chan []byte, outputChannelSize) - o.wait = make(chan bool) - return -} - -func (o *DnsOutput) GetOutputChannel() chan []byte { - return o.outputChannel -} - -func (o *DnsOutput) RunOutputLoop() { - dt := &dnstap.Dnstap{} - for frame := range o.outputChannel { - if err := proto.Unmarshal(frame, dt); err != nil { - el.Fatalf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) - break - } - if *dt.Type == dnstap.Dnstap_MESSAGE { - if dt.Message.ResponseMessage != nil { - msg := new(dns.Msg) - err := msg.Unpack(dt.Message.ResponseMessage) - if err != nil { - el.Println(err) - } else { - for i, rr := range msg.Answer { - if msg.Answer[i].Header().Rrtype == dns.TypeA { - ipAddr := msg.Answer[i].(*dns.A).A.String() - hostname := rr.Header().Name - c.Set(ipAddr, hostname, defaulTimeout) - el.Println(c.Items()) - // el.Println(i, msg.Answer[i].(*dns.A).A.String(), rr.Header().Name) - } - } - } - } - } - } - close(o.wait) -} - -func (o *DnsOutput) Close() { - close(o.outputChannel) - <-o.wait -} - -func outputOpener() func() dnstap.Output { - return func() dnstap.Output { - var o dnstap.Output - o = NewDnsOutput() - go o.RunOutputLoop() - return o - } -} - -func outputLoop(opener func() dnstap.Output, data <-chan []byte, done chan<- struct{}) { - sigch := make(chan os.Signal, 1) - signal.Notify(sigch, os.Interrupt, syscall.SIGHUP) - o := opener() - defer func() { - o.Close() - close(done) - os.Exit(0) - }() - for { - select { - case b, ok := <-data: - if !ok { - return - } - o.GetOutputChannel() <- b - case sig := <-sigch: - if sig == syscall.SIGHUP { - o.Close() - o = opener() - continue - } - return - } - } -} diff --git a/go-audit.yaml.example b/go-audit.yaml.example index 1ead083..8d02369 100644 --- a/go-audit.yaml.example +++ b/go-audit.yaml.example @@ -6,6 +6,10 @@ socket_buffer: # Maximum max is net.core.rmem_max (/proc/sys/net/core/rmem_max) receive: 16384 +# Configure dnstap socket path if available +dnstap: + socket: /var/run/dnstap.sock + events: # Minimum event type to capture, default 1300 min: 1300 diff --git a/parser.go b/parser.go index 5811b44..c95a689 100644 --- a/parser.go +++ b/parser.go @@ -142,7 +142,6 @@ func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { } } - // Find the next uid= if we have space for one next := start + end + 1 if next >= len(data) { break From faf25c48ca9bea7ee215b659d4ef98353dd332ec Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 10:30:20 -0700 Subject: [PATCH 10/45] exited prior --- dnstap.go | 1 - 1 file changed, 1 deletion(-) diff --git a/dnstap.go b/dnstap.go index 451a040..fe619e6 100644 --- a/dnstap.go +++ b/dnstap.go @@ -27,7 +27,6 @@ func NewDNSTap(socketPath string) (*DNSTap, error) { l, err := net.Listen("unix", socketPath) if err != nil { el.Fatal("Listen error: ", err) - return nil, err } d := &DNSTap{ Listener: l, From 5143465f53f0109fbbd8460a300fe29a336a3166 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 10:43:48 -0700 Subject: [PATCH 11/45] remove fatals --- dnstap.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dnstap.go b/dnstap.go index fe619e6..a6ad106 100644 --- a/dnstap.go +++ b/dnstap.go @@ -58,20 +58,18 @@ func (d *DNSTap) frameDecode(conn net.Conn) { for { frame, err := dec.Decode() if err != nil { - el.Fatalf("framestream.Decoder.Decode() failed: %s\n", err) - break + el.Printf("framestream.Decoder.Decode() failed: %s\n", err) } dt := &dnstap.Dnstap{} if err := proto.Unmarshal(frame, dt); err != nil { - el.Fatalf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) - break + el.Printf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) } if *dt.Type == dnstap.Dnstap_MESSAGE { msg := new(dns.Msg) if dt.Message.ResponseMessage != nil { err := msg.Unpack(dt.Message.ResponseMessage) if err != nil { - el.Fatalf("msg.Unpack:() failed: %s \n", err) + el.Printf("msg.Unpack:() failed: %s \n", err) } else { d.storeDNSRec(msg) } From ae25aa68b025fce87bf5148f7705467f923208ee Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 14:05:19 -0700 Subject: [PATCH 12/45] minor change to error return and print --- dnstap.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dnstap.go b/dnstap.go index a6ad106..3988adf 100644 --- a/dnstap.go +++ b/dnstap.go @@ -4,6 +4,7 @@ import ( "net" "os" "time" + "fmt" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" @@ -24,14 +25,15 @@ type DNSTap struct { func NewDNSTap(socketPath string) (*DNSTap, error) { os.Remove(socketPath) //c := cache.New(defaulTimeout, defaulTimeout *2) - l, err := net.Listen("unix", socketPath) + listener, err := net.Listen("unix", socketPath) if err != nil { - el.Fatal("Listen error: ", err) + return nil, fmt.Errorf("Listen error: ", err) } d := &DNSTap{ - Listener: l, + Listener: listener, //Cache: c, } + l.Printf("dnstap: opened input socket: %s", socketPath) return d, nil } From a209fc26a8261baba4ede9e83c1de740ee483702 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 14:17:05 -0700 Subject: [PATCH 13/45] remove trailing . --- dnstap.go | 6 ++++-- parser.go | 5 ++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dnstap.go b/dnstap.go index 3988adf..57b0952 100644 --- a/dnstap.go +++ b/dnstap.go @@ -1,10 +1,11 @@ package main import ( + "fmt" "net" "os" + "strings" "time" - "fmt" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" @@ -84,7 +85,8 @@ func (d *DNSTap) storeDNSRec(msg *dns.Msg) { for i, rr := range msg.Answer { if msg.Answer[i].Header().Rrtype == dns.TypeA { ipAddr := msg.Answer[i].(*dns.A).A.String() - hostname := rr.Header().Name + // dns responses have a trailing . that we remove + hostname := strings.TrimRight(rr.Header().Name, ".") c.Set(ipAddr, hostname, defaulTimeout) } diff --git a/parser.go b/parser.go index c95a689..2c5a10d 100644 --- a/parser.go +++ b/parser.go @@ -12,7 +12,6 @@ import ( ) var uidMap = map[string]string{} -var DNSMap = map[string]string{} var headerEndChar = []byte{")"[0]} var headerSepChar = byte(':') var spaceChar = byte(' ') @@ -116,7 +115,7 @@ func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { break } - // Progress the start point beyon the = sign + // Progress the start point beyond the = sign start += 6 if end = strings.IndexByte(data[start:], spaceChar); end < 0 { // There was no ending space, maybe the uid is at the end of the line @@ -163,7 +162,7 @@ func (amg *AuditMessageGroup) mapUids(am *AuditMessage) { break } - // Progress the start point beyon the = sign + // Progress the start point beyond the = sign start += 4 if end = strings.IndexByte(data[start:], spaceChar); end < 0 { // There was no ending space, maybe the uid is at the end of the line From 433d3ef923979179ad9d93d3563591e092e87b68 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 14:37:12 -0700 Subject: [PATCH 14/45] check saddr if type ipv4 --- dnstap.go | 2 ++ parser.go | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/dnstap.go b/dnstap.go index 57b0952..520d175 100644 --- a/dnstap.go +++ b/dnstap.go @@ -62,10 +62,12 @@ func (d *DNSTap) frameDecode(conn net.Conn) { frame, err := dec.Decode() if err != nil { el.Printf("framestream.Decoder.Decode() failed: %s\n", err) + break } dt := &dnstap.Dnstap{} if err := proto.Unmarshal(frame, dt); err != nil { el.Printf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) + break } if *dt.Type == dnstap.Dnstap_MESSAGE { msg := new(dns.Msg) diff --git a/parser.go b/parser.go index 2c5a10d..c34d2d2 100644 --- a/parser.go +++ b/parser.go @@ -128,10 +128,16 @@ func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { } saddr := data[start : start+end] - // todo: check the socket family and if its ipv4 - ipv4Hex := saddr[8:16] - octet, _ := hex.DecodeString(ipv4Hex) - ipAddr := fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) + + var ipv4Hex, ipAddr string + + switch family := saddr[0:4]; family { + // 0200 = ipv4 + case "0200": + ipv4Hex = saddr[8:16] + octet, _ := hex.DecodeString(ipv4Hex) + ipAddr = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) + } // Don't bother re-adding if the existing group already has the mapping if _, ok := amg.DNSMap[ipAddr]; !ok { From c72a6dbaa30fb326551e4c2f0440bbb5f089b468 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 2 Oct 2018 14:45:15 -0700 Subject: [PATCH 15/45] minor --- dnstap.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dnstap.go b/dnstap.go index 520d175..0d4dda7 100644 --- a/dnstap.go +++ b/dnstap.go @@ -34,7 +34,7 @@ func NewDNSTap(socketPath string) (*DNSTap, error) { Listener: listener, //Cache: c, } - l.Printf("dnstap: opened input socket: %s", socketPath) + l.Printf("Started dnstap listener, opened input socket: %s", socketPath) return d, nil } From 601f9f7f7a8423cd73f7a4c61576066a7c51836f Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 4 Oct 2018 19:33:08 -0700 Subject: [PATCH 16/45] some refactoring --- audit.go | 7 ++++--- dnstap.go | 55 ++++++++++++++++++++++++++----------------------------- parser.go | 29 ++++++++++++----------------- 3 files changed, 42 insertions(+), 49 deletions(-) diff --git a/audit.go b/audit.go index ec9549d..e70a604 100644 --- a/audit.go +++ b/audit.go @@ -4,7 +4,6 @@ import ( "errors" "flag" "fmt" - "github.com/spf13/viper" "log" "log/syslog" "os" @@ -15,6 +14,8 @@ import ( "strconv" "strings" "syscall" + + "github.com/spf13/viper" ) var l = log.New(os.Stdout, "", 0) @@ -343,12 +344,12 @@ func main() { el.Fatal(err) } - dnstapClient, err := NewDNSTap(config.GetString("dnstap.socket")) + dnstapClient, err := NewDnsTapClient(config.GetString("dnstap.socket")) if err != nil { el.Fatal(err) } - go dnstapClient.readSock() + go dnstapClient.Receive() marshaller := NewAuditMarshaller( writer, diff --git a/dnstap.go b/dnstap.go index 0d4dda7..5a295d3 100644 --- a/dnstap.go +++ b/dnstap.go @@ -14,42 +14,42 @@ import ( "github.com/patrickmn/go-cache" ) -const defaulTimeout = 24 * time.Hour +const defaultTimeout = time.Hour -var c = cache.New(defaulTimeout, defaulTimeout*2) +var c = cache.New(defaultTimeout, defaultTimeout*2) -type DNSTap struct { +type DnsTapClient struct { Listener net.Listener //Cache *cache.Cache } -func NewDNSTap(socketPath string) (*DNSTap, error) { - os.Remove(socketPath) +func NewDnsTapClient(socket string) (*DnsTapClient, error) { + os.Remove(socket) //c := cache.New(defaulTimeout, defaulTimeout *2) - listener, err := net.Listen("unix", socketPath) + listener, err := net.Listen("unix", socket) if err != nil { return nil, fmt.Errorf("Listen error: ", err) } - d := &DNSTap{ + d := &DnsTapClient{ Listener: listener, //Cache: c, } - l.Printf("Started dnstap listener, opened input socket: %s", socketPath) + l.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil } -func (d *DNSTap) readSock() { +func (d *DnsTapClient) Receive() { for { conn, err := d.Listener.Accept() if err != nil { el.Printf("net.Listener.Accept() failed: %s\n", err) continue } - go d.frameDecode(conn) + d.Decode(conn) } } -func (d *DNSTap) frameDecode(conn net.Conn) { +func (d *DnsTapClient) Decode(conn net.Conn) { decoderOptions := &framestream.DecoderOptions{ ContentType: []byte("protobuf:dnstap.Dnstap"), Bidirectional: true, @@ -69,28 +69,25 @@ func (d *DNSTap) frameDecode(conn net.Conn) { el.Printf("dnstap.DnsOutput: proto.Unmarshal() failed: %s\n", err) break } - if *dt.Type == dnstap.Dnstap_MESSAGE { - msg := new(dns.Msg) - if dt.Message.ResponseMessage != nil { - err := msg.Unpack(dt.Message.ResponseMessage) - if err != nil { - el.Printf("msg.Unpack:() failed: %s \n", err) - } else { - d.storeDNSRec(msg) - } - } + if dt.Message.ResponseMessage != nil { + d.cache(dt) } } } -func (d *DNSTap) storeDNSRec(msg *dns.Msg) { - for i, rr := range msg.Answer { - if msg.Answer[i].Header().Rrtype == dns.TypeA { - ipAddr := msg.Answer[i].(*dns.A).A.String() - // dns responses have a trailing . that we remove - hostname := strings.TrimRight(rr.Header().Name, ".") - c.Set(ipAddr, hostname, defaulTimeout) +func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { + m := new(dns.Msg) + err := m.Unpack(dt.Message.ResponseMessage) + if err != nil { + el.Printf("msg.Unpack() failed: %s \n", err) + } else { + for i, r := range m.Answer { + switch m.Answer[i].Header().Rrtype { + case dns.TypeA: + ip := m.Answer[i].(*dns.A).A.String() + host := strings.TrimRight(r.Header().Name, ".") + c.Set(ip, host, defaultTimeout) + } } - } } diff --git a/parser.go b/parser.go index c34d2d2..6307025 100644 --- a/parser.go +++ b/parser.go @@ -35,7 +35,7 @@ type AuditMessageGroup struct { CompleteAfter time.Time `json:"-"` Msgs []*AuditMessage `json:"messages"` UidMap map[string]string `json:"uid_map"` - DNSMap map[string]string `json:"dns_map"` + DnsMap map[string]string `json:"dnstap"` Syscall string `json:"-"` } @@ -47,7 +47,7 @@ func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup { AuditTime: am.AuditTime, CompleteAfter: time.Now().Add(COMPLETE_AFTER), UidMap: make(map[string]string, 2), // Usually only 2 individual uids per execve - DNSMap: make(map[string]string, 2), // Usually only 2 individual uids per execve + DnsMap: make(map[string]string, 2), // Usually only 2 individual uids per execve Msgs: make([]*AuditMessage, 0, 6), } @@ -94,7 +94,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { case 1309, 1307, 1306: - amg.mapDNS(am) + amg.mapDns(am) // Don't map uids here case 1300: amg.findSyscall(am) @@ -104,8 +104,8 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { } } -// Find all `saddr=` occurrences in a message and map to dnstap cache -func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { +// Find all `saddr=` occurrences in a message and do a lookup +func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { data := am.Data start := 0 end := 0 @@ -118,10 +118,7 @@ func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { // Progress the start point beyond the = sign start += 6 if end = strings.IndexByte(data[start:], spaceChar); end < 0 { - // There was no ending space, maybe the uid is at the end of the line end = len(data) - start - - // If the end of the line is greater than 5 characters away (overflows a 16 bit uint) then it can't be a uid if end > 34 { break } @@ -129,21 +126,19 @@ func (amg *AuditMessageGroup) mapDNS(am *AuditMessage) { saddr := data[start : start+end] - var ipv4Hex, ipAddr string + var ip string switch family := saddr[0:4]; family { - // 0200 = ipv4 + // 0200: ipv4 case "0200": - ipv4Hex = saddr[8:16] - octet, _ := hex.DecodeString(ipv4Hex) - ipAddr = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) + octet, _ := hex.DecodeString(saddr[8:16]) + ip = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) } - // Don't bother re-adding if the existing group already has the mapping - if _, ok := amg.DNSMap[ipAddr]; !ok { - DNSHost, ok := c.Get(ipAddr) + if _, ok := amg.DnsMap[ip]; !ok { + host, ok := c.Get(ip) if ok { - amg.DNSMap[ipAddr] = DNSHost.(string) + amg.DnsMap[ip] = host.(string) } } From 65ac373c5322b626a49ebaf3c3cbd5d0b80904ba Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 5 Oct 2018 14:20:07 -0700 Subject: [PATCH 17/45] try at 180ms delay on audit type message 1306 --- dnstap.go | 2 +- marshaller.go | 9 +++++++++ parser.go | 12 +++++------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dnstap.go b/dnstap.go index 5a295d3..e1c5080 100644 --- a/dnstap.go +++ b/dnstap.go @@ -45,7 +45,7 @@ func (d *DnsTapClient) Receive() { el.Printf("net.Listener.Accept() failed: %s\n", err) continue } - d.Decode(conn) + go d.Decode(conn) } } diff --git a/marshaller.go b/marshaller.go index cf30d1f..572dc8f 100644 --- a/marshaller.go +++ b/marshaller.go @@ -116,6 +116,15 @@ func (a *AuditMarshaller) completeMessage(seq int) { //TODO: attempted to complete a missing message, log? return } + for _, m := range msg.Msgs { + switch m.Type { + case 1306: + // delay the mapping + time.Sleep(time.Millisecond * 180) + // time.Sleep(time.Millisecond * 50) + msg.mapDns(m) + } + } if a.dropMessage(msg) { delete(a.msgs, seq) diff --git a/parser.go b/parser.go index 6307025..2a014a4 100644 --- a/parser.go +++ b/parser.go @@ -47,7 +47,7 @@ func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup { AuditTime: am.AuditTime, CompleteAfter: time.Now().Add(COMPLETE_AFTER), UidMap: make(map[string]string, 2), // Usually only 2 individual uids per execve - DnsMap: make(map[string]string, 2), // Usually only 2 individual uids per execve + DnsMap: make(map[string]string, 1), Msgs: make([]*AuditMessage, 0, 6), } @@ -94,7 +94,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { case 1309, 1307, 1306: - amg.mapDns(am) + // amg.mapDns(am) // Don't map uids here case 1300: amg.findSyscall(am) @@ -135,11 +135,9 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { ip = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) } - if _, ok := amg.DnsMap[ip]; !ok { - host, ok := c.Get(ip) - if ok { - amg.DnsMap[ip] = host.(string) - } + host, ok := c.Get(ip) + if ok { + amg.DnsMap[ip] = host.(string) } next := start + end + 1 From 588946b856af7bfe730f174281ba49489d5c9f38 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 10 Oct 2018 11:26:29 -0700 Subject: [PATCH 18/45] make current tests work with dnstap --- dnstap.go | 2 +- marshaller.go | 3 +-- marshaller_test.go | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/dnstap.go b/dnstap.go index e1c5080..b5a24b1 100644 --- a/dnstap.go +++ b/dnstap.go @@ -28,7 +28,7 @@ func NewDnsTapClient(socket string) (*DnsTapClient, error) { //c := cache.New(defaulTimeout, defaulTimeout *2) listener, err := net.Listen("unix", socket) if err != nil { - return nil, fmt.Errorf("Listen error: ", err) + return nil, fmt.Errorf("Listen error: %s", err) } d := &DnsTapClient{ Listener: listener, diff --git a/marshaller.go b/marshaller.go index 572dc8f..e25ee1e 100644 --- a/marshaller.go +++ b/marshaller.go @@ -120,8 +120,7 @@ func (a *AuditMarshaller) completeMessage(seq int) { switch m.Type { case 1306: // delay the mapping - time.Sleep(time.Millisecond * 180) - // time.Sleep(time.Millisecond * 50) + time.Sleep(time.Millisecond * 100) msg.mapDns(m) } } diff --git a/marshaller_test.go b/marshaller_test.go index 45714fb..2721427 100644 --- a/marshaller_test.go +++ b/marshaller_test.go @@ -45,7 +45,7 @@ func TestAuditMarshaller_Consume(t *testing.T) { assert.Equal( t, - "{\"sequence\":1,\"timestamp\":\"10000001\",\"messages\":[{\"type\":1300,\"data\":\"hi there\"},{\"type\":1301,\"data\":\"hi there\"}],\"uid_map\":{}}\n", + "{\"sequence\":1,\"timestamp\":\"10000001\",\"messages\":[{\"type\":1300,\"data\":\"hi there\"},{\"type\":1301,\"data\":\"hi there\"}],\"uid_map\":{},\"dnstap\":{}}\n", w.String(), ) assert.Equal(t, 0, len(m.msgs)) @@ -113,7 +113,7 @@ func TestAuditMarshaller_Consume(t *testing.T) { m.Consume(new1320("0")) } - assert.Equal(t, "{\"sequence\":4,\"timestamp\":\"10000001\",\"messages\":[{\"type\":1300,\"data\":\"hi there\"}],\"uid_map\":{}}\n", w.String()) + assert.Equal(t, "{\"sequence\":4,\"timestamp\":\"10000001\",\"messages\":[{\"type\":1300,\"data\":\"hi there\"}],\"uid_map\":{},\"dnstap\":{}}\n", w.String()) expected := start.Add(time.Second * 2) assert.True(t, expected.Equal(time.Now()) || expected.Before(time.Now()), "Should have taken at least 2 seconds to flush") assert.Equal(t, 0, len(m.msgs)) From fc1f10bff9dbc16de6d48cdd1fcea9ad53e09785 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 10 Oct 2018 17:42:16 -0700 Subject: [PATCH 19/45] this may work, maybe --- marshaller.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/marshaller.go b/marshaller.go index e25ee1e..bee7fcd 100644 --- a/marshaller.go +++ b/marshaller.go @@ -80,8 +80,16 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.flushOld() return } else if nlMsg.Header.Type == EVENT_EOE { + if val, ok := a.msgs[aMsg.Seq]; ok { + if aMsg.Type == 1306 { + if len(val.DnsMap) > 0 { // This is end of event msg, flush the msg with that sequence and discard this one - a.completeMessage(aMsg.Seq) + a.completeMessage(aMsg.Seq) + } + } + } + // This is end of event msg, flush the msg with that sequence and discard this one + // a.completeMessage(aMsg.Seq) return } From ba3909fdc9180ad24a44fdbb10dc2f06302178de Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 10 Oct 2018 20:04:05 -0700 Subject: [PATCH 20/45] remove the sleep --- marshaller.go | 10 +++------- parser.go | 4 ++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/marshaller.go b/marshaller.go index bee7fcd..5bfd32a 100644 --- a/marshaller.go +++ b/marshaller.go @@ -81,13 +81,11 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { return } else if nlMsg.Header.Type == EVENT_EOE { if val, ok := a.msgs[aMsg.Seq]; ok { - if aMsg.Type == 1306 { - if len(val.DnsMap) > 0 { - // This is end of event msg, flush the msg with that sequence and discard this one - a.completeMessage(aMsg.Seq) + if len(val.DnsMap) > 0 { + // This is end of event msg, flush the msg with that sequence and discard this one + a.completeMessage(aMsg.Seq) } } - } // This is end of event msg, flush the msg with that sequence and discard this one // a.completeMessage(aMsg.Seq) return @@ -127,8 +125,6 @@ func (a *AuditMarshaller) completeMessage(seq int) { for _, m := range msg.Msgs { switch m.Type { case 1306: - // delay the mapping - time.Sleep(time.Millisecond * 100) msg.mapDns(m) } } diff --git a/parser.go b/parser.go index 2a014a4..ce86e08 100644 --- a/parser.go +++ b/parser.go @@ -47,7 +47,7 @@ func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup { AuditTime: am.AuditTime, CompleteAfter: time.Now().Add(COMPLETE_AFTER), UidMap: make(map[string]string, 2), // Usually only 2 individual uids per execve - DnsMap: make(map[string]string, 1), + DnsMap: make(map[string]string, 1), Msgs: make([]*AuditMessage, 0, 6), } @@ -94,7 +94,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { case 1309, 1307, 1306: - // amg.mapDns(am) + amg.mapDns(am) // Don't map uids here case 1300: amg.findSyscall(am) From 3056711c293a02da929e662ab386d11642a570ea Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 11 Oct 2018 13:20:31 -0700 Subject: [PATCH 21/45] defer listener close and check if dnstap is configured --- audit.go | 14 +++++++++----- dnstap.go | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/audit.go b/audit.go index e70a604..449e0d3 100644 --- a/audit.go +++ b/audit.go @@ -343,13 +343,17 @@ func main() { if err != nil { el.Fatal(err) } + + dnstapSckt := config.GetString("dnstap.socket") - dnstapClient, err := NewDnsTapClient(config.GetString("dnstap.socket")) - if err != nil { - el.Fatal(err) - } + if dnstapSckt != "" { + dnstapClient, err := NewDnsTapClient(dnstapSckt) + if err != nil { + el.Fatal(err) + } - go dnstapClient.Receive() + go dnstapClient.Receive() + } marshaller := NewAuditMarshaller( writer, diff --git a/dnstap.go b/dnstap.go index b5a24b1..6371206 100644 --- a/dnstap.go +++ b/dnstap.go @@ -39,6 +39,7 @@ func NewDnsTapClient(socket string) (*DnsTapClient, error) { } func (d *DnsTapClient) Receive() { + defer d.Listener.Close() for { conn, err := d.Listener.Accept() if err != nil { From e8e9d84807f5bdd7fe9369961ce71154bb199f14 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 11 Oct 2018 16:05:27 -0700 Subject: [PATCH 22/45] add constants and address some comments --- audit.go | 2 +- parser.go | 99 +++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/audit.go b/audit.go index 449e0d3..c196cbc 100644 --- a/audit.go +++ b/audit.go @@ -343,7 +343,7 @@ func main() { if err != nil { el.Fatal(err) } - + dnstapSckt := config.GetString("dnstap.socket") if dnstapSckt != "" { diff --git a/parser.go b/parser.go index ce86e08..fce763a 100644 --- a/parser.go +++ b/parser.go @@ -11,17 +11,45 @@ import ( "time" ) -var uidMap = map[string]string{} -var headerEndChar = []byte{")"[0]} -var headerSepChar = byte(':') -var spaceChar = byte(' ') - const ( + SYSCALL = 1300 // Syscall event + PATH = 1302 // Filename path information + IPC = 1303 // IPC record + SOCKETCALL = 1304 // sys_socketcall arguments + CONFIG_CHANGE = 1305 // Audit system configuration change + SOCKADDR = 1306 // sockaddr copied as syscall arg + CWD = 1307 // Current working directory + EXECVE = 1309 // execve arguments + IPC_SET_PERM = 1311 // IPC new permissions record type + MQ_OPEN = 1312 // POSIX MQ open record type + MQ_SENDRECV = 1313 // POSIX MQ sendreceive record type + MQ_NOTIFY = 1314 // POSIX MQ notify record type + MQ_GETSETATTR = 1315 // POSIX MQ getset attribute record type + KERNEL_OTHER = 1316 // For use by 3rd party modules + FD_PAIR = 1317 // audit record for pipesocketpair + OBJ_PID = 1318 // ptrace target + TTY = 1319 // Input on an administrative TTY + EOE = 1320 // End of multi-record event + BPRM_FCAPS = 1321 // Information about fcaps increasing perms + CAPSET = 1322 // Record showing argument to sys_capset + MMAP = 1323 // Record showing descriptor and flags in mmap + NETFILTER_PKT = 1324 // Packets traversing netfilter chains + NETFILTER_CFG = 1325 // Netfilter chain modifications + SECCOMP = 1326 // Secure Computing event + PROCTITLE = 1327 // Proctitle emit event + FEATURE_CHANGE = 1328 // audit log listing feature changes + REPLACE = 1329 // Replace auditd if this packet unanswerd HEADER_MIN_LENGTH = 7 // Minimum length of an audit header HEADER_START_POS = 6 // Position in the audit header that the data starts COMPLETE_AFTER = time.Second * 2 // Log a message after this time or EOE + SOCKADDR_LENGTH = 34 // Length of saddr event ) +var uidMap = map[string]string{} +var headerEndChar = []byte{")"[0]} +var headerSepChar = byte(':') +var spaceChar = byte(' ') + type AuditMessage struct { Type uint16 `json:"type"` Data string `json:"data"` @@ -93,10 +121,10 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { amg.Msgs = append(amg.Msgs, am) //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { - case 1309, 1307, 1306: + case EXECVE, CWD, SOCKADDR: amg.mapDns(am) // Don't map uids here - case 1300: + case SYSCALL: amg.findSyscall(am) amg.mapUids(am) default: @@ -110,44 +138,43 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { start := 0 end := 0 - for { - if start = strings.Index(data, "saddr="); start < 0 { - break - } + if start = strings.Index(data, "saddr="); start < 0 { + return + } - // Progress the start point beyond the = sign - start += 6 - if end = strings.IndexByte(data[start:], spaceChar); end < 0 { - end = len(data) - start - if end > 34 { - break - } + // Progress the start point beyond the = sign + start += 6 + if end = strings.IndexByte(data[start:], spaceChar); end < 0 { + end = len(data) - start + if end > SOCKADDR_LENGTH { + return } + } - saddr := data[start : start+end] - - var ip string + saddr := data[start : start+end] - switch family := saddr[0:4]; family { - // 0200: ipv4 - case "0200": - octet, _ := hex.DecodeString(saddr[8:16]) - ip = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) - } + ip := parseAddr(saddr) - host, ok := c.Get(ip) - if ok { - amg.DnsMap[ip] = host.(string) - } + host, ok := c.Get(ip) + if ok { + amg.DnsMap[ip] = host.(string) + } +} - next := start + end + 1 - if next >= len(data) { - break +func parseAddr(saddr string) (addr string) { + switch family := saddr[0:4]; family { + // 0200: ipv4 + case "0200": + octet, err := hex.DecodeString(saddr[8:16]) + if err != nil { + el.Printf("unable to decode hex to ip: %s", err) } - - data = data[next:] + addr = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) + // case "0A00": + // octet, err := hex.DecodeString(saddr[16:48]) } + return addr } // Find all `uid=` occurrences in a message and adds the username to the UidMap object From b7006c9e1946423d3049f07e00d5022b7c856e84 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 11 Oct 2018 16:53:16 -0700 Subject: [PATCH 23/45] remove the fmt and use net.IP --- parser.go | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/parser.go b/parser.go index fce763a..ec5291f 100644 --- a/parser.go +++ b/parser.go @@ -3,7 +3,7 @@ package main import ( "bytes" "encoding/hex" - "fmt" + "net" "os/user" "strconv" "strings" @@ -13,32 +13,10 @@ import ( const ( SYSCALL = 1300 // Syscall event - PATH = 1302 // Filename path information - IPC = 1303 // IPC record - SOCKETCALL = 1304 // sys_socketcall arguments CONFIG_CHANGE = 1305 // Audit system configuration change - SOCKADDR = 1306 // sockaddr copied as syscall arg + SOCKADDR = 1306 // Sockaddr copied as syscall arg CWD = 1307 // Current working directory - EXECVE = 1309 // execve arguments - IPC_SET_PERM = 1311 // IPC new permissions record type - MQ_OPEN = 1312 // POSIX MQ open record type - MQ_SENDRECV = 1313 // POSIX MQ sendreceive record type - MQ_NOTIFY = 1314 // POSIX MQ notify record type - MQ_GETSETATTR = 1315 // POSIX MQ getset attribute record type - KERNEL_OTHER = 1316 // For use by 3rd party modules - FD_PAIR = 1317 // audit record for pipesocketpair - OBJ_PID = 1318 // ptrace target - TTY = 1319 // Input on an administrative TTY - EOE = 1320 // End of multi-record event - BPRM_FCAPS = 1321 // Information about fcaps increasing perms - CAPSET = 1322 // Record showing argument to sys_capset - MMAP = 1323 // Record showing descriptor and flags in mmap - NETFILTER_PKT = 1324 // Packets traversing netfilter chains - NETFILTER_CFG = 1325 // Netfilter chain modifications - SECCOMP = 1326 // Secure Computing event - PROCTITLE = 1327 // Proctitle emit event - FEATURE_CHANGE = 1328 // audit log listing feature changes - REPLACE = 1329 // Replace auditd if this packet unanswerd + EXECVE = 1309 // Execve arguments HEADER_MIN_LENGTH = 7 // Minimum length of an audit header HEADER_START_POS = 6 // Position in the audit header that the data starts COMPLETE_AFTER = time.Second * 2 // Log a message after this time or EOE @@ -164,14 +142,12 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { func parseAddr(saddr string) (addr string) { switch family := saddr[0:4]; family { // 0200: ipv4 - case "0200": - octet, err := hex.DecodeString(saddr[8:16]) + case :0200" + b, err := hex.DecodeString(saddr[8:16]) if err != nil { - el.Printf("unable to decode hex to ip: %s", err) + el.Printf("unable to decode hex to bytes: %s", err) } - addr = fmt.Sprintf("%v.%v.%v.%v", octet[0], octet[1], octet[2], octet[3]) - // case "0A00": - // octet, err := hex.DecodeString(saddr[16:48]) + addr = net.IP(b).String() } return addr From c1832ce499faf6128690cfb93d2c09efb7bbb5ef Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 11 Oct 2018 16:54:52 -0700 Subject: [PATCH 24/45] typo --- parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser.go b/parser.go index ec5291f..67d204c 100644 --- a/parser.go +++ b/parser.go @@ -142,7 +142,7 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { func parseAddr(saddr string) (addr string) { switch family := saddr[0:4]; family { // 0200: ipv4 - case :0200" + case "0200": b, err := hex.DecodeString(saddr[8:16]) if err != nil { el.Printf("unable to decode hex to bytes: %s", err) From f858ff9392872eb241a4bfa2cdbeea493a4b7002 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Thu, 11 Oct 2018 18:49:38 -0700 Subject: [PATCH 25/45] replace with bigcache --- audit.go | 19 +++++++++++++++++++ dnstap.go | 11 +---------- parser.go | 6 +++--- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/audit.go b/audit.go index c196cbc..2e8a553 100644 --- a/audit.go +++ b/audit.go @@ -14,10 +14,15 @@ import ( "strconv" "strings" "syscall" + "time" + "github.com/allegro/bigcache" "github.com/spf13/viper" ) +var c *bigcache.BigCache +var cacheInitErr error + var l = log.New(os.Stdout, "", 0) var el = log.New(os.Stderr, "", 0) @@ -347,6 +352,20 @@ func main() { dnstapSckt := config.GetString("dnstap.socket") if dnstapSckt != "" { + cacheCfg := bigcache.Config{ + Shards: 1024, + LifeWindow: 24 * time.Hour, + MaxEntriesInWindow: 1000 * 10 * 60, + MaxEntrySize: 500, + HardMaxCacheSize: 512, + } + + c, cacheInitErr = bigcache.NewBigCache(cacheCfg) + + if cacheInitErr != nil { + el.Fatal(cacheInitErr) + } + dnstapClient, err := NewDnsTapClient(dnstapSckt) if err != nil { el.Fatal(err) diff --git a/dnstap.go b/dnstap.go index 6371206..67fc034 100644 --- a/dnstap.go +++ b/dnstap.go @@ -5,34 +5,25 @@ import ( "net" "os" "strings" - "time" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" "github.com/miekg/dns" - "github.com/patrickmn/go-cache" ) -const defaultTimeout = time.Hour - -var c = cache.New(defaultTimeout, defaultTimeout*2) - type DnsTapClient struct { Listener net.Listener - //Cache *cache.Cache } func NewDnsTapClient(socket string) (*DnsTapClient, error) { os.Remove(socket) - //c := cache.New(defaulTimeout, defaulTimeout *2) listener, err := net.Listen("unix", socket) if err != nil { return nil, fmt.Errorf("Listen error: %s", err) } d := &DnsTapClient{ Listener: listener, - //Cache: c, } l.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil @@ -87,7 +78,7 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { case dns.TypeA: ip := m.Answer[i].(*dns.A).A.String() host := strings.TrimRight(r.Header().Name, ".") - c.Set(ip, host, defaultTimeout) + c.Set(ip, []byte(host)) } } } diff --git a/parser.go b/parser.go index 67d204c..bafe291 100644 --- a/parser.go +++ b/parser.go @@ -133,9 +133,9 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { ip := parseAddr(saddr) - host, ok := c.Get(ip) - if ok { - amg.DnsMap[ip] = host.(string) + host, err := c.Get(ip) + if err == nil { + amg.DnsMap[ip] = string(host) } } From 8ee9694d44cccc455f8bf4830010f6d9726038d0 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Fri, 12 Oct 2018 14:54:03 -0700 Subject: [PATCH 26/45] add dbg messages --- audit.go | 28 ++++++++++++++++------------ dnstap.go | 19 ++++++++++++++++--- marshaller.go | 7 +++++-- parser.go | 12 ++++++++---- 4 files changed, 45 insertions(+), 21 deletions(-) diff --git a/audit.go b/audit.go index 2e8a553..bb7e2ca 100644 --- a/audit.go +++ b/audit.go @@ -351,6 +351,19 @@ func main() { dnstapSckt := config.GetString("dnstap.socket") + + marshaller := NewAuditMarshaller( + writer, + uint16(config.GetInt("events.min")), + uint16(config.GetInt("events.max")), + config.GetBool("message_tracking.enabled"), + config.GetBool("message_tracking.log_out_of_order"), + config.GetInt("message_tracking.max_out_of_order"), + filters, + ) + + l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max")) + if dnstapSckt != "" { cacheCfg := bigcache.Config{ Shards: 1024, @@ -366,6 +379,9 @@ func main() { el.Fatal(cacheInitErr) } + c.Set("127.0.0.1", []byte("loopback")) + + //dnstapClient, err := NewDnsTapClient(dnstapSckt, marshaller) dnstapClient, err := NewDnsTapClient(dnstapSckt) if err != nil { el.Fatal(err) @@ -374,18 +390,6 @@ func main() { go dnstapClient.Receive() } - marshaller := NewAuditMarshaller( - writer, - uint16(config.GetInt("events.min")), - uint16(config.GetInt("events.max")), - config.GetBool("message_tracking.enabled"), - config.GetBool("message_tracking.log_out_of_order"), - config.GetInt("message_tracking.max_out_of_order"), - filters, - ) - - l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max")) - //Main loop. Get data from netlink and send it to the json lib for processing for { msg, err := nlClient.Receive() diff --git a/dnstap.go b/dnstap.go index 67fc034..c85a9dc 100644 --- a/dnstap.go +++ b/dnstap.go @@ -5,6 +5,7 @@ import ( "net" "os" "strings" + "time" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" @@ -14,8 +15,10 @@ import ( type DnsTapClient struct { Listener net.Listener + //AuditMarshaller *AuditMarshaller } +//func NewDnsTapClient(socket string, am *AuditMarshaller) (*DnsTapClient, error) { func NewDnsTapClient(socket string) (*DnsTapClient, error) { os.Remove(socket) listener, err := net.Listen("unix", socket) @@ -24,6 +27,7 @@ func NewDnsTapClient(socket string) (*DnsTapClient, error) { } d := &DnsTapClient{ Listener: listener, + //AuditMarshaller: am, } l.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil @@ -74,11 +78,20 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { el.Printf("msg.Unpack() failed: %s \n", err) } else { for i, r := range m.Answer { + host := strings.TrimRight(r.Header().Name, ".") switch m.Answer[i].Header().Rrtype { case dns.TypeA: - ip := m.Answer[i].(*dns.A).A.String() - host := strings.TrimRight(r.Header().Name, ".") - c.Set(ip, []byte(host)) + ipv4 := m.Answer[i].(*dns.A).A.String() + c.Set(ipv4, []byte(host)) + el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) + case dns.TypeAAAA: + ipv6 := m.Answer[i].(*dns.AAAA).AAAA.String() + c.Set(ipv6, []byte(host)) + el.Printf("Setting ipv6 for %s -> %s @ %v", host, ipv6, time.Now().Unix()) + case dns.TypeCNAME: + cname := m.Answer[i].(*dns.CNAME).Target + c.Set(cname, []byte(host)) + el.Printf("Setting cname for %s -> %s @ %v", host, cname, time.Now().Unix()) } } } diff --git a/marshaller.go b/marshaller.go index 5bfd32a..ef31bfd 100644 --- a/marshaller.go +++ b/marshaller.go @@ -24,6 +24,7 @@ type AuditMarshaller struct { maxOutOfOrder int attempts int filters map[string]map[uint16][]*regexp.Regexp // { syscall: { mtype: [regexp, ...] } } + saddrSeq map[string]bool } type AuditFilter struct { @@ -80,11 +81,12 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.flushOld() return } else if nlMsg.Header.Type == EVENT_EOE { + el.Println("EOE Message") if val, ok := a.msgs[aMsg.Seq]; ok { if len(val.DnsMap) > 0 { - // This is end of event msg, flush the msg with that sequence and discard this one + // This is end of event msg, flush the msg with that sequence and discard this one a.completeMessage(aMsg.Seq) - } + } } // This is end of event msg, flush the msg with that sequence and discard this one // a.completeMessage(aMsg.Seq) @@ -105,6 +107,7 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { // Outputs any messages that are old enough // This is because there is no indication of multi message events coming from kaudit func (a *AuditMarshaller) flushOld() { + el.Println("Flush old") now := time.Now() for seq, msg := range a.msgs { if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { diff --git a/parser.go b/parser.go index bafe291..02a8a9b 100644 --- a/parser.go +++ b/parser.go @@ -3,6 +3,7 @@ package main import ( "bytes" "encoding/hex" + "fmt" "net" "os/user" "strconv" @@ -31,14 +32,14 @@ var spaceChar = byte(' ') type AuditMessage struct { Type uint16 `json:"type"` Data string `json:"data"` - Seq int `json:"-"` - AuditTime string `json:"-"` + Seq int `json:"sequence"` + AuditTime string `json:"timestamp"` } type AuditMessageGroup struct { Seq int `json:"sequence"` AuditTime string `json:"timestamp"` - CompleteAfter time.Time `json:"-"` + CompleteAfter time.Time `json:"completeAfter"` Msgs []*AuditMessage `json:"messages"` UidMap map[string]string `json:"uid_map"` DnsMap map[string]string `json:"dnstap"` @@ -100,7 +101,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { case EXECVE, CWD, SOCKADDR: - amg.mapDns(am) + // amg.mapDns(am) // Don't map uids here case SYSCALL: amg.findSyscall(am) @@ -136,6 +137,9 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { host, err := c.Get(ip) if err == nil { amg.DnsMap[ip] = string(host) + amg.DnsMap["time"] = fmt.Sprintf("%v", time.Now().Unix()) + } else { + el.Printf("[%s] not in cache", ip) } } From 64f1850991562ff6e0e46661a0b50ccd52c15695 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 15 Oct 2018 15:05:48 -0700 Subject: [PATCH 27/45] maybe this is better --- audit.go | 5 ++--- dnstap.go | 23 +++++++++++++---------- marshaller.go | 50 +++++++++++++++++++++++++++++++------------------- parser.go | 26 ++++++++++++++++---------- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/audit.go b/audit.go index bb7e2ca..0adb781 100644 --- a/audit.go +++ b/audit.go @@ -351,7 +351,6 @@ func main() { dnstapSckt := config.GetString("dnstap.socket") - marshaller := NewAuditMarshaller( writer, uint16(config.GetInt("events.min")), @@ -381,8 +380,8 @@ func main() { c.Set("127.0.0.1", []byte("loopback")) - //dnstapClient, err := NewDnsTapClient(dnstapSckt, marshaller) - dnstapClient, err := NewDnsTapClient(dnstapSckt) + dnstapClient, err := NewDnsTapClient(dnstapSckt, marshaller) + //dnstapClient, err := NewDnsTapClient(dnstapSckt) if err != nil { el.Fatal(err) } diff --git a/dnstap.go b/dnstap.go index c85a9dc..a23eff2 100644 --- a/dnstap.go +++ b/dnstap.go @@ -5,7 +5,6 @@ import ( "net" "os" "strings" - "time" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" @@ -14,20 +13,19 @@ import ( ) type DnsTapClient struct { - Listener net.Listener - //AuditMarshaller *AuditMarshaller + Listener net.Listener + AuditMarshaller *AuditMarshaller } -//func NewDnsTapClient(socket string, am *AuditMarshaller) (*DnsTapClient, error) { -func NewDnsTapClient(socket string) (*DnsTapClient, error) { +func NewDnsTapClient(socket string, am *AuditMarshaller) (*DnsTapClient, error) { os.Remove(socket) listener, err := net.Listen("unix", socket) if err != nil { return nil, fmt.Errorf("Listen error: %s", err) } d := &DnsTapClient{ - Listener: listener, - //AuditMarshaller: am, + Listener: listener, + AuditMarshaller: am, } l.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil @@ -83,16 +81,21 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { case dns.TypeA: ipv4 := m.Answer[i].(*dns.A).A.String() c.Set(ipv4, []byte(host)) - el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) + //el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) + if val, ok := d.AuditMarshaller.waitingForDNS[ipv4]; ok { + d.AuditMarshaller.completeMessage(val) + delete(d.AuditMarshaller.waitingForDNS, ipv4) + } case dns.TypeAAAA: ipv6 := m.Answer[i].(*dns.AAAA).AAAA.String() c.Set(ipv6, []byte(host)) - el.Printf("Setting ipv6 for %s -> %s @ %v", host, ipv6, time.Now().Unix()) + //el.Printf("Setting ipv6 for %s -> %s @ %v", host, ipv6, time.Now().Unix()) case dns.TypeCNAME: cname := m.Answer[i].(*dns.CNAME).Target c.Set(cname, []byte(host)) - el.Printf("Setting cname for %s -> %s @ %v", host, cname, time.Now().Unix()) + //el.Printf("Setting cname for %s -> %s @ %v", host, cname, time.Now().Unix()) } + } } } diff --git a/marshaller.go b/marshaller.go index ef31bfd..5313718 100644 --- a/marshaller.go +++ b/marshaller.go @@ -24,7 +24,7 @@ type AuditMarshaller struct { maxOutOfOrder int attempts int filters map[string]map[uint16][]*regexp.Regexp // { syscall: { mtype: [regexp, ...] } } - saddrSeq map[string]bool + waitingForDNS map[string]int } type AuditFilter struct { @@ -45,6 +45,7 @@ func NewAuditMarshaller(w *AuditWriter, eventMin uint16, eventMax uint16, trackM logOutOfOrder: logOOO, maxOutOfOrder: maxOOO, filters: make(map[string]map[uint16][]*regexp.Regexp), + waitingForDNS: make(map[string]int), } for _, filter := range filters { @@ -80,21 +81,26 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { // Drop all audit messages that aren't things we care about or end a multi packet event a.flushOld() return - } else if nlMsg.Header.Type == EVENT_EOE { - el.Println("EOE Message") - if val, ok := a.msgs[aMsg.Seq]; ok { - if len(val.DnsMap) > 0 { - // This is end of event msg, flush the msg with that sequence and discard this one - a.completeMessage(aMsg.Seq) - } - } - // This is end of event msg, flush the msg with that sequence and discard this one - // a.completeMessage(aMsg.Seq) + } + + val, ok := a.msgs[aMsg.Seq] + + if ok && nlMsg.Header.Type == EVENT_EOE && !val.gotSaddr && !val.gotDNS { + a.completeMessage(aMsg.Seq) return } - if val, ok := a.msgs[aMsg.Seq]; ok { - // Use the original AuditMessageGroup if we have one + if ok { + // mark if we don't have dns yet + if val.gotSaddr && !val.gotDNS { + ip, _ := a.getDns(val) + if ip != "" { + a.waitingForDNS[ip] = val.Seq + } + } + if val.gotSaddr && val.gotDNS { + a.completeMessage(aMsg.Seq) + } val.AddMessage(aMsg) } else { // Create a new AuditMessageGroup @@ -104,10 +110,18 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.flushOld() } +func (a *AuditMarshaller) getDns(val *AuditMessageGroup) (ip string, host []byte) { + for _, msg := range val.Msgs { + if msg.Type == 1306 { + ip, host = val.mapDns(msg) + } + } + return ip, host +} + // Outputs any messages that are old enough // This is because there is no indication of multi message events coming from kaudit func (a *AuditMarshaller) flushOld() { - el.Println("Flush old") now := time.Now() for seq, msg := range a.msgs { if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { @@ -125,11 +139,9 @@ func (a *AuditMarshaller) completeMessage(seq int) { //TODO: attempted to complete a missing message, log? return } - for _, m := range msg.Msgs { - switch m.Type { - case 1306: - msg.mapDns(m) - } + + if !msg.gotDNS && msg.gotSaddr { + a.getDns(msg) } if a.dropMessage(msg) { diff --git a/parser.go b/parser.go index 02a8a9b..b96ac05 100644 --- a/parser.go +++ b/parser.go @@ -3,7 +3,6 @@ package main import ( "bytes" "encoding/hex" - "fmt" "net" "os/user" "strconv" @@ -33,7 +32,7 @@ type AuditMessage struct { Type uint16 `json:"type"` Data string `json:"data"` Seq int `json:"sequence"` - AuditTime string `json:"timestamp"` + AuditTime string `json:"-"` } type AuditMessageGroup struct { @@ -44,6 +43,8 @@ type AuditMessageGroup struct { UidMap map[string]string `json:"uid_map"` DnsMap map[string]string `json:"dnstap"` Syscall string `json:"-"` + gotSaddr bool + gotDNS bool } // Creates a new message group from the details parsed from the message @@ -100,9 +101,10 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { amg.Msgs = append(amg.Msgs, am) //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { - case EXECVE, CWD, SOCKADDR: - // amg.mapDns(am) + case EXECVE, CWD: // Don't map uids here + case SOCKADDR: + amg.mapDns(am) case SYSCALL: amg.findSyscall(am) amg.mapUids(am) @@ -112,7 +114,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { } // Find all `saddr=` occurrences in a message and do a lookup -func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { +func (amg *AuditMessageGroup) mapDns(am *AuditMessage) (ip string, host []byte) { data := am.Data start := 0 end := 0 @@ -132,15 +134,19 @@ func (amg *AuditMessageGroup) mapDns(am *AuditMessage) { saddr := data[start : start+end] - ip := parseAddr(saddr) + amg.gotSaddr = true - host, err := c.Get(ip) + var err error + + ip = parseAddr(saddr) + + host, err = c.Get(ip) if err == nil { + amg.gotDNS = true amg.DnsMap[ip] = string(host) - amg.DnsMap["time"] = fmt.Sprintf("%v", time.Now().Unix()) - } else { - el.Printf("[%s] not in cache", ip) + //amg.DnsMap["time"] = fmt.Sprintf("%v", time.Now().Unix()) } + return } func parseAddr(saddr string) (addr string) { From 3f4c0e8611ad99a4c387c7f375c6a9faf97f3604 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 15 Oct 2018 15:13:26 -0700 Subject: [PATCH 28/45] put this back to how it was --- parser.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parser.go b/parser.go index b96ac05..6dcf4d8 100644 --- a/parser.go +++ b/parser.go @@ -31,14 +31,14 @@ var spaceChar = byte(' ') type AuditMessage struct { Type uint16 `json:"type"` Data string `json:"data"` - Seq int `json:"sequence"` + Seq int `json:"-"` AuditTime string `json:"-"` } type AuditMessageGroup struct { Seq int `json:"sequence"` AuditTime string `json:"timestamp"` - CompleteAfter time.Time `json:"completeAfter"` + CompleteAfter time.Time `json:"-"` Msgs []*AuditMessage `json:"messages"` UidMap map[string]string `json:"uid_map"` DnsMap map[string]string `json:"dnstap"` From c13de033921752eb6f040c62e6ec1cd09d8e82b5 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 15 Oct 2018 15:33:56 -0700 Subject: [PATCH 29/45] update vendor.json --- vendor/vendor.json | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/vendor/vendor.json b/vendor/vendor.json index 969cccc..8fb34fc 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -8,18 +8,48 @@ "revision": "99064174e013895bbd9b025c31100bd1d9b590ca", "revisionTime": "2016-07-17T15:07:09Z" }, + { + "checksumSHA1": "DNxS1GhVEsXnyzbz6fC+Zs/b8Y0=", + "path": "github.com/allegro/bigcache", + "revision": "70fdb6c1fbb8ef895f9222fa4552f88913cc05e4", + "revisionTime": "2018-10-09T05:01:24Z" + }, + { + "checksumSHA1": "zqToN+R6KybEskp1D4G/lAOKXU4=", + "path": "github.com/allegro/bigcache/queue", + "revision": "70fdb6c1fbb8ef895f9222fa4552f88913cc05e4", + "revisionTime": "2018-10-09T05:01:24Z" + }, { "checksumSHA1": "Lf3uUXTkKK5DJ37BxQvxO1Fq+K8=", "path": "github.com/davecgh/go-spew/spew", "revision": "6d212800a42e8ab5c146b8ace3490ee17e5225f9", "revisionTime": "2016-09-07T16:21:46Z" }, + { + "checksumSHA1": "NJ+mjEgf5/x6f+x8+IrQQcD7vko=", + "path": "github.com/dnstap/golang-dnstap", + "revision": "2cf77a2b5e11ac8d0ba3892772ac8e1f7b528344", + "revisionTime": "2017-08-29T15:17:10Z" + }, + { + "checksumSHA1": "O9mvmXE7QpYrb8st4l9SG7wud2s=", + "path": "github.com/farsightsec/golang-framestream", + "revision": "d0f7ed81b7afcc56d3c1a66a0fd26a1b609675f3", + "revisionTime": "2018-08-20T16:18:18Z" + }, { "checksumSHA1": "xgjI2W3RGiQwNlxsOW2V9fJ9kaM=", "path": "github.com/fsnotify/fsnotify", "revision": "f12c6236fe7b5cf6bcf30e5935d08cb079d78334", "revisionTime": "2016-08-16T05:15:41Z" }, + { + "checksumSHA1": "GaJLoEuMGnP5ofXvuweAI4wx06U=", + "path": "github.com/golang/protobuf/proto", + "revision": "ddf22928ea3c56eb4292a0adbbf5001b1e8e7d0d", + "revisionTime": "2018-10-05T18:17:28Z" + }, { "checksumSHA1": "fa9G5tEr4oJJc3vtgn/B0NWZXfA=", "path": "github.com/hashicorp/hcl", @@ -98,6 +128,12 @@ "revision": "0723e352fa358f9322c938cc2dadda874e9151a9", "revisionTime": "2016-09-08T09:36:58Z" }, + { + "checksumSHA1": "KycBRsg27SKMCVnRgChcQOqviPA=", + "path": "github.com/miekg/dns", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, { "checksumSHA1": "LUrnGREfnifW4WDMaavmc9MlLI0=", "path": "github.com/mitchellh/mapstructure", @@ -212,6 +248,41 @@ "revision": "119f50887f8fe324fe2386421c27a11af014b64e", "revisionTime": "2016-05-18T18:29:53Z" }, + { + "checksumSHA1": "NjyXtXsaf0ulRJn6HQSP1FqGL4A=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/net/bpf", + "path": "golang.org/x/net/bpf", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, + { + "checksumSHA1": "CHpYrf4HcmHB60gnTNxgjGgY53w=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/net/internal/iana", + "path": "golang.org/x/net/internal/iana", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, + { + "checksumSHA1": "wUFe08HvcVTwkXK7dojH3W7CQVg=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/net/internal/socket", + "path": "golang.org/x/net/internal/socket", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, + { + "checksumSHA1": "NITWzmU2rmFojwdCaxjbvR26B7U=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/net/ipv4", + "path": "golang.org/x/net/ipv4", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, + { + "checksumSHA1": "arKhUYK+A0oKiB8kCQbtc+S6RM4=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/net/ipv6", + "path": "golang.org/x/net/ipv6", + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" + }, { "checksumSHA1": "8fD/im5Kwvy3JgmxulDTambmE8w=", "path": "golang.org/x/sys/unix", From 210918565461105d5c366fddca6f251249aae0b3 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 15 Oct 2018 16:18:03 -0700 Subject: [PATCH 30/45] update external dep --- vendor/vendor.json | 266 ++++++++++++++------------------------------- 1 file changed, 80 insertions(+), 186 deletions(-) diff --git a/vendor/vendor.json b/vendor/vendor.json index 8fb34fc..c18edba 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2,12 +2,6 @@ "comment": "", "ignore": "test", "package": [ - { - "checksumSHA1": "hqDDDpue/5363luidNMBS8z8eJU=", - "path": "github.com/BurntSushi/toml", - "revision": "99064174e013895bbd9b025c31100bd1d9b590ca", - "revisionTime": "2016-07-17T15:07:09Z" - }, { "checksumSHA1": "DNxS1GhVEsXnyzbz6fC+Zs/b8Y0=", "path": "github.com/allegro/bigcache", @@ -20,12 +14,6 @@ "revision": "70fdb6c1fbb8ef895f9222fa4552f88913cc05e4", "revisionTime": "2018-10-09T05:01:24Z" }, - { - "checksumSHA1": "Lf3uUXTkKK5DJ37BxQvxO1Fq+K8=", - "path": "github.com/davecgh/go-spew/spew", - "revision": "6d212800a42e8ab5c146b8ace3490ee17e5225f9", - "revisionTime": "2016-09-07T16:21:46Z" - }, { "checksumSHA1": "NJ+mjEgf5/x6f+x8+IrQQcD7vko=", "path": "github.com/dnstap/golang-dnstap", @@ -39,10 +27,10 @@ "revisionTime": "2018-08-20T16:18:18Z" }, { - "checksumSHA1": "xgjI2W3RGiQwNlxsOW2V9fJ9kaM=", + "checksumSHA1": "x2Km0Qy3WgJJnV19Zv25VwTJcBM=", "path": "github.com/fsnotify/fsnotify", - "revision": "f12c6236fe7b5cf6bcf30e5935d08cb079d78334", - "revisionTime": "2016-08-16T05:15:41Z" + "revision": "4da3e2cfbabc9f751898f250b49f2439785783a1", + "revisionTime": "2017-03-29T04:21:07Z" }, { "checksumSHA1": "GaJLoEuMGnP5ofXvuweAI4wx06U=", @@ -51,82 +39,70 @@ "revisionTime": "2018-10-05T18:17:28Z" }, { - "checksumSHA1": "fa9G5tEr4oJJc3vtgn/B0NWZXfA=", + "checksumSHA1": "HtpYAWHvd9mq+mHkpo7z8PGzMik=", "path": "github.com/hashicorp/hcl", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "67DfevLBglV52Y2eAuhFc/xQni0=", + "checksumSHA1": "XQmjDva9JCGGkIecOgwtBEMCJhU=", "path": "github.com/hashicorp/hcl/hcl/ast", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "l2oQxBsZRwn6eZjf+whXr8c9+8c=", + "checksumSHA1": "/15SVLnCDzxICSatuYbfctrcpSM=", "path": "github.com/hashicorp/hcl/hcl/parser", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" + }, + { + "checksumSHA1": "WR1BjzDKgv6uE+3ShcDTYz0Gl6A=", + "path": "github.com/hashicorp/hcl/hcl/printer", + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "lgR7PSAZ0RtvAc9OCtCnNsF/x8g=", + "checksumSHA1": "PYDzRc61T0pbwWuLNHgBRp/gJII=", "path": "github.com/hashicorp/hcl/hcl/scanner", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "JlZmnzqdmFFyb1+2afLyR3BOE/8=", + "checksumSHA1": "oS3SCN9Wd6D8/LG0Yx1fu84a7gI=", "path": "github.com/hashicorp/hcl/hcl/strconv", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { "checksumSHA1": "c6yprzj06ASwCo18TtbbNNBHljA=", "path": "github.com/hashicorp/hcl/hcl/token", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "jQ45CCc1ed/nlV7bbSnx6z72q1M=", + "checksumSHA1": "PwlfXt7mFS8UYzWxOK5DOq0yxS0=", "path": "github.com/hashicorp/hcl/json/parser", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "YdvFsNOMSWMLnY6fcliWQa0O5Fw=", + "checksumSHA1": "afrZ8VmAwfTdDAYVgNSXbxa4GsA=", "path": "github.com/hashicorp/hcl/json/scanner", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { "checksumSHA1": "fNlXQCQEnb+B3k5UDL/r15xtSJY=", "path": "github.com/hashicorp/hcl/json/token", - "revision": "99df0eb941dd8ddbc83d3f3605a34f6a686ac85e", - "revisionTime": "2016-09-02T16:52:19Z" - }, - { - "checksumSHA1": "KQhA4EQp4Ldwj9nJZnEURlE6aQw=", - "path": "github.com/kr/fs", - "revision": "2788f0dbd16903de03cb8186e5c7d97b69ad387b", - "revisionTime": "2013-11-06T22:25:44Z" - }, - { - "checksumSHA1": "eOXF2PEvYLMeD8DSzLZJWbjYzco=", - "path": "github.com/kr/pretty", - "revision": "cfb55aafdaf3ec08f0db22699ab822c50091b1c4", - "revisionTime": "2016-08-23T17:07:15Z" - }, - { - "checksumSHA1": "uulQHQ7IsRKqDudBC8Go9J0gtAc=", - "path": "github.com/kr/text", - "revision": "7cafcd837844e784b526369c9bce262804aebc60", - "revisionTime": "2016-05-04T02:26:26Z" + "revision": "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8", + "revisionTime": "2017-10-17T18:19:29Z" }, { - "checksumSHA1": "S6PDDQMYaKwLDIP/NsRYb4FRAqQ=", + "checksumSHA1": "NiPRC0JDsfCFir75S1TrFHPP8+M=", "path": "github.com/magiconair/properties", - "revision": "0723e352fa358f9322c938cc2dadda874e9151a9", - "revisionTime": "2016-09-08T09:36:58Z" + "revision": "2c9e9502788518c97fe44e8955cd069417ee89df", + "revisionTime": "2018-02-17T13:45:45Z" }, { "checksumSHA1": "KycBRsg27SKMCVnRgChcQOqviPA=", @@ -135,118 +111,66 @@ "revisionTime": "2018-09-29T16:16:31Z" }, { - "checksumSHA1": "LUrnGREfnifW4WDMaavmc9MlLI0=", + "checksumSHA1": "FpgODaspeA2JtrcagXl9JRY/i88=", "path": "github.com/mitchellh/mapstructure", - "revision": "ca63d7c062ee3c9f34db231e352b60012b4fd0c1", - "revisionTime": "2016-08-08T18:12:53Z" - }, - { - "checksumSHA1": "8Y05Pz7onrQPcVWW6JStSsYRh6E=", - "path": "github.com/pelletier/go-buffruneio", - "revision": "df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d", - "revisionTime": "2016-01-24T19:35:03Z" + "revision": "a4e142e9c047c904fa2f1e144d9a84e6133024bc", + "revisionTime": "2018-02-03T10:28:30Z" }, { - "checksumSHA1": "8p2QlEz7wJdeT4RQINh1mQgB0YQ=", + "checksumSHA1": "+qobk0BQiCfqdrhKeoZnwz6hFnE=", "path": "github.com/pelletier/go-toml", - "revision": "31055c2ff0bb0c7f9095aec0d220aed21108121e", - "revisionTime": "2016-09-06T20:25:57Z" - }, - { - "checksumSHA1": "Hky3u+8Rqum+wB5BHMj0A8ZmT4g=", - "path": "github.com/pkg/errors", - "revision": "17b591df37844cde689f4d5813e5cea0927d8dd2", - "revisionTime": "2016-08-22T09:00:10Z" - }, - { - "checksumSHA1": "Se8D92CQFRScBhugM3JFKSmwwzU=", - "path": "github.com/pkg/profile", - "revision": "303fad789382e54372c3b92956e55fadf81b413d", - "revisionTime": "2016-08-22T09:56:20Z" - }, - { - "checksumSHA1": "v6/DDmWObvEsdMvLe+KfuBVSNtg=", - "path": "github.com/pkg/sftp", - "revision": "8197a2e580736b78d704be0fc47b2324c0591a32", - "revisionTime": "2016-09-08T10:00:35Z" - }, - { - "checksumSHA1": "LuFv4/jlrmFNnDb/5SCSEPAM9vU=", - "path": "github.com/pmezard/go-difflib/difflib", - "revision": "792786c7400a136282c1664665ae0a8db921c6c2", - "revisionTime": "2016-01-10T10:55:54Z" + "revision": "acdc4509485b587f5e675510c4f2c63e90ff68a8", + "revisionTime": "2018-01-18T22:54:55Z" }, { - "checksumSHA1": "59wTbS4fE2282Q88NrBYImbFGbo=", + "checksumSHA1": "F3JU4T4XXvZTRAcv6rhTao4QGos=", "path": "github.com/spf13/afero", - "revision": "20500e2abd0d1f4564a499e83d11d6c73cd58c27", - "revisionTime": "2016-08-21T08:36:12Z" + "revision": "bbf41cb36dffe15dff5bf7e18c447801e7ffe163", + "revisionTime": "2018-02-11T16:21:14Z" }, { - "checksumSHA1": "S29tnboEqKV8/ghlvDzaqtJJD7E=", + "checksumSHA1": "X6RueW0rO55PbOQ0sMWSQOxVl4I=", "path": "github.com/spf13/afero/mem", - "revision": "20500e2abd0d1f4564a499e83d11d6c73cd58c27", - "revisionTime": "2016-08-21T08:36:12Z" + "revision": "bbf41cb36dffe15dff5bf7e18c447801e7ffe163", + "revisionTime": "2018-02-11T16:21:14Z" }, { - "checksumSHA1": "sLyAUiIT7V0DNVp6yBhW4Ms5BEs=", - "path": "github.com/spf13/afero/sftp", - "revision": "20500e2abd0d1f4564a499e83d11d6c73cd58c27", - "revisionTime": "2016-08-21T08:36:12Z" - }, - { - "checksumSHA1": "F5PKdeFzODdoAChY/aEiEDaNWtQ=", + "checksumSHA1": "Hc2i9OOK34PAImuNftTaHdbdLgs=", "path": "github.com/spf13/cast", - "revision": "e31f36ffc91a2ba9ddb72a4b6a607ff9b3d3cb63", - "revisionTime": "2016-07-30T09:20:37Z" + "revision": "8965335b8c7107321228e3e3702cab9832751bac", + "revisionTime": "2018-02-14T17:35:30Z" }, { - "checksumSHA1": "dkruahfhuLXXuyeCuRpsWlcRK+8=", + "checksumSHA1": "+JFKK0z5Eutk29rUz1lEhLxHMfk=", "path": "github.com/spf13/jwalterweatherman", - "revision": "33c24e77fb80341fe7130ee7c594256ff08ccc46", - "revisionTime": "2016-03-01T12:00:06Z" + "revision": "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394", + "revisionTime": "2018-01-09T13:55:06Z" }, { - "checksumSHA1": "AdV2H8HNLmUZbKzDdGme3s1gffI=", + "checksumSHA1": "tfKmT8uovT9Ch2YyDJtti3egAB4=", "path": "github.com/spf13/pflag", - "revision": "7b17cc4658ef5ca157b986ea5c0b43af7938532b", - "revisionTime": "2016-09-11T19:46:38Z" + "revision": "ee5fd03fd6acfd43e44aea0b4135958546ed8e73", + "revisionTime": "2018-02-20T14:32:36Z" }, { - "checksumSHA1": "cNe3MKwsFLDRzRjKEtOduUiG344=", + "checksumSHA1": "GWX9W5F1QBqLZsS1bYsG3jXjb3g=", "path": "github.com/spf13/viper", - "revision": "7538d73b4eb9511d85a9f1dfef202eeb8ac260f4", - "revisionTime": "2017-02-17T16:38:17Z" - }, - { - "checksumSHA1": "iydUphwYqZRq3WhstEdGsbvBAKs=", - "path": "github.com/stretchr/testify/assert", - "revision": "d77da356e56a7428ad25149ca77381849a6a5232", - "revisionTime": "2016-06-15T09:26:46Z" - }, - { - "checksumSHA1": "h+pFYiRHBogczS8/F1NoN3Ata44=", - "path": "golang.org/x/crypto/curve25519", - "revision": "119f50887f8fe324fe2386421c27a11af014b64e", - "revisionTime": "2016-05-18T18:29:53Z" + "revision": "aafc9e6bc7b7bb53ddaa75a5ef49a17d6e654be5", + "revisionTime": "2017-11-29T09:51:06Z" }, { - "checksumSHA1": "wGb//LjBPNxYHqk+dcLo7BjPXK8=", + "checksumSHA1": "2LpxYGSf068307b7bhAuVjvzLLc=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/crypto/ed25519", "path": "golang.org/x/crypto/ed25519", - "revision": "119f50887f8fe324fe2386421c27a11af014b64e", - "revisionTime": "2016-05-18T18:29:53Z" + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" }, { - "checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=", + "checksumSHA1": "0JTAFXPkankmWcZGQJGScLDiaN8=", + "origin": "github.com/miekg/dns/vendor/golang.org/x/crypto/ed25519/internal/edwards25519", "path": "golang.org/x/crypto/ed25519/internal/edwards25519", - "revision": "119f50887f8fe324fe2386421c27a11af014b64e", - "revisionTime": "2016-05-18T18:29:53Z" - }, - { - "checksumSHA1": "pXOcpeiBjX3zbVKeg0pvYnEmtqU=", - "path": "golang.org/x/crypto/ssh", - "revision": "119f50887f8fe324fe2386421c27a11af014b64e", - "revisionTime": "2016-05-18T18:29:53Z" + "revision": "ba6747e8a94115e9dc7738afb87850687611df1b", + "revisionTime": "2018-09-29T16:16:31Z" }, { "checksumSHA1": "NjyXtXsaf0ulRJn6HQSP1FqGL4A=", @@ -284,58 +208,28 @@ "revisionTime": "2018-09-29T16:16:31Z" }, { - "checksumSHA1": "8fD/im5Kwvy3JgmxulDTambmE8w=", + "checksumSHA1": "rEL6Z+R2saAWNv45gP6ZxoLgcEE=", "path": "golang.org/x/sys/unix", - "revision": "30de6d19a3bd89a5f38ae4028e23aaa5582648af", - "revisionTime": "2016-09-07T05:59:14Z" - }, - { - "checksumSHA1": "3JkLagg7UP4890bHn0Uld6GmO6M=", - "path": "golang.org/x/text/internal/gen", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" - }, - { - "checksumSHA1": "47nwiUyVBY2RKoEGXmCSvusY4Js=", - "path": "golang.org/x/text/internal/triegen", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" - }, - { - "checksumSHA1": "LyT5byg0Dq4x3OcGt6EwIDgPUpc=", - "path": "golang.org/x/text/internal/ucd", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" + "revision": "e4b3c5e9061176387e7cea65e4dc5853801f3fb7", + "revisionTime": "2018-09-28T10:55:38Z" }, { "checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=", "path": "golang.org/x/text/transform", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" - }, - { - "checksumSHA1": "n94g6qdzv0fgQFGelH4/HXOthl0=", - "path": "golang.org/x/text/unicode/cldr", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" + "revision": "88f656faf3f37f690df1a32515b479415e1a6769", + "revisionTime": "2017-10-26T07:52:28Z" }, { - "checksumSHA1": "Aj3JSVO324FCjEAGm4ZwmC79bbo=", + "checksumSHA1": "BwRNKgzIMUxk56OScxyr43BV6IE=", "path": "golang.org/x/text/unicode/norm", - "revision": "f6f58eac0a9f37bcb49f8c8010c24cd382bf862d", - "revisionTime": "2016-08-30T13:53:28Z" - }, - { - "checksumSHA1": "93uHIq25lffEKY47PV8dBPD+XuQ=", - "path": "gopkg.in/fsnotify.v1", - "revision": "a8a77c9133d2d6fd8334f3260d06f60e8d80a5fb", - "revisionTime": "2016-06-29T01:11:04Z" + "revision": "88f656faf3f37f690df1a32515b479415e1a6769", + "revisionTime": "2017-10-26T07:52:28Z" }, { - "checksumSHA1": "SPMXWeoFQa5z0pLPmqpcFzyHqQQ=", + "checksumSHA1": "fALlQNY1fM99NesfLJ50KguWsio=", "path": "gopkg.in/yaml.v2", - "revision": "31c299268d302dd0aa9a0dcf765a3d58971ac83f", - "revisionTime": "2016-09-12T16:56:03Z" + "revision": "cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b", + "revisionTime": "2017-04-07T17:21:22Z" } ], "rootPath": "github.com/slackhq/go-audit" From 640e7263776a3177429040d74f247e8aa92f58c5 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 16 Oct 2018 12:53:25 -0700 Subject: [PATCH 31/45] just run complete when eoe and no lookups are waiting --- marshaller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marshaller.go b/marshaller.go index 5313718..a7aa386 100644 --- a/marshaller.go +++ b/marshaller.go @@ -85,7 +85,7 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val, ok := a.msgs[aMsg.Seq] - if ok && nlMsg.Header.Type == EVENT_EOE && !val.gotSaddr && !val.gotDNS { + if ok && nlMsg.Header.Type == EVENT_EOE && len(a.waitingForDNS) == 0 { a.completeMessage(aMsg.Seq) return } From cf5e64714a7425262135b9b75e598d16f14e8178 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 16 Oct 2018 16:18:45 -0700 Subject: [PATCH 32/45] refactor, maybe this is better --- dnstap.go | 13 ++++++++++--- marshaller.go | 8 +++----- parser.go | 2 ++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/dnstap.go b/dnstap.go index a23eff2..d60c10b 100644 --- a/dnstap.go +++ b/dnstap.go @@ -6,6 +6,8 @@ import ( "os" "strings" +// "time" + "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" @@ -81,9 +83,14 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { case dns.TypeA: ipv4 := m.Answer[i].(*dns.A).A.String() c.Set(ipv4, []byte(host)) - //el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) - if val, ok := d.AuditMarshaller.waitingForDNS[ipv4]; ok { - d.AuditMarshaller.completeMessage(val) + // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) + if seq, ok := d.AuditMarshaller.waitingForDNS[ipv4]; ok { + if msg, ok := d.AuditMarshaller.msgs[seq]; ok { + if !msg.gotDNS && msg.gotSaddr { + d.AuditMarshaller.getDns(msg) + } + d.AuditMarshaller.completeMessage(seq) + } delete(d.AuditMarshaller.waitingForDNS, ipv4) } case dns.TypeAAAA: diff --git a/marshaller.go b/marshaller.go index a7aa386..4a9fc00 100644 --- a/marshaller.go +++ b/marshaller.go @@ -96,10 +96,12 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { ip, _ := a.getDns(val) if ip != "" { a.waitingForDNS[ip] = val.Seq + return } } if val.gotSaddr && val.gotDNS { a.completeMessage(aMsg.Seq) + return } val.AddMessage(aMsg) } else { @@ -112,7 +114,7 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { func (a *AuditMarshaller) getDns(val *AuditMessageGroup) (ip string, host []byte) { for _, msg := range val.Msgs { - if msg.Type == 1306 { + if msg.Type == SOCKADDR { ip, host = val.mapDns(msg) } } @@ -140,10 +142,6 @@ func (a *AuditMarshaller) completeMessage(seq int) { return } - if !msg.gotDNS && msg.gotSaddr { - a.getDns(msg) - } - if a.dropMessage(msg) { delete(a.msgs, seq) return diff --git a/parser.go b/parser.go index 6dcf4d8..4babdcc 100644 --- a/parser.go +++ b/parser.go @@ -3,6 +3,8 @@ package main import ( "bytes" "encoding/hex" + + // "fmt" "net" "os/user" "strconv" From 8d466ee8a48c6bd54554faf2d74be82c7c3e84d1 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Sat, 20 Oct 2018 13:25:26 -0700 Subject: [PATCH 33/45] change cache settings --- audit.go | 12 +++++------- marshaller.go | 11 +++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/audit.go b/audit.go index 0adb781..a8f9916 100644 --- a/audit.go +++ b/audit.go @@ -365,11 +365,11 @@ func main() { if dnstapSckt != "" { cacheCfg := bigcache.Config{ - Shards: 1024, - LifeWindow: 24 * time.Hour, - MaxEntriesInWindow: 1000 * 10 * 60, - MaxEntrySize: 500, - HardMaxCacheSize: 512, + Shards: 256, + LifeWindow: time.Second * 300, + MaxEntriesInWindow: 1024, + MaxEntrySize: 96, + HardMaxCacheSize: 10, } c, cacheInitErr = bigcache.NewBigCache(cacheCfg) @@ -378,8 +378,6 @@ func main() { el.Fatal(cacheInitErr) } - c.Set("127.0.0.1", []byte("loopback")) - dnstapClient, err := NewDnsTapClient(dnstapSckt, marshaller) //dnstapClient, err := NewDnsTapClient(dnstapSckt) if err != nil { diff --git a/marshaller.go b/marshaller.go index 4a9fc00..f39c90e 100644 --- a/marshaller.go +++ b/marshaller.go @@ -85,7 +85,7 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val, ok := a.msgs[aMsg.Seq] - if ok && nlMsg.Header.Type == EVENT_EOE && len(a.waitingForDNS) == 0 { + if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr){ a.completeMessage(aMsg.Seq) return } @@ -94,15 +94,9 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { // mark if we don't have dns yet if val.gotSaddr && !val.gotDNS { ip, _ := a.getDns(val) - if ip != "" { a.waitingForDNS[ip] = val.Seq - return - } - } - if val.gotSaddr && val.gotDNS { - a.completeMessage(aMsg.Seq) - return } + val.AddMessage(aMsg) } else { // Create a new AuditMessageGroup @@ -127,6 +121,7 @@ func (a *AuditMarshaller) flushOld() { now := time.Now() for seq, msg := range a.msgs { if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { + a.waitingForDNS = make(map[string]int) a.completeMessage(seq) } } From e84a593f1cfc127247843d871b3b0444e276f8b7 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 24 Oct 2018 06:29:14 -0700 Subject: [PATCH 34/45] refactor more --- dnstap.go | 15 ++++++++++++--- marshaller.go | 23 +++++++++-------------- parser.go | 2 -- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/dnstap.go b/dnstap.go index d60c10b..c49fb1b 100644 --- a/dnstap.go +++ b/dnstap.go @@ -6,7 +6,7 @@ import ( "os" "strings" -// "time" + // "time" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" @@ -83,11 +83,11 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { case dns.TypeA: ipv4 := m.Answer[i].(*dns.A).A.String() c.Set(ipv4, []byte(host)) - // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) + // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) if seq, ok := d.AuditMarshaller.waitingForDNS[ipv4]; ok { if msg, ok := d.AuditMarshaller.msgs[seq]; ok { if !msg.gotDNS && msg.gotSaddr { - d.AuditMarshaller.getDns(msg) + getDns(msg) } d.AuditMarshaller.completeMessage(seq) } @@ -106,3 +106,12 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { } } } + +func getDns(val *AuditMessageGroup) (ip string, host []byte) { + for _, msg := range val.Msgs { + if msg.Type == SOCKADDR { + ip, host = val.mapDns(msg) + } + } + return ip, host +} diff --git a/marshaller.go b/marshaller.go index f39c90e..3ea1e8c 100644 --- a/marshaller.go +++ b/marshaller.go @@ -85,19 +85,23 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val, ok := a.msgs[aMsg.Seq] - if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr){ + if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr) { a.completeMessage(aMsg.Seq) return } if ok { - // mark if we don't have dns yet - if val.gotSaddr && !val.gotDNS { - ip, _ := a.getDns(val) - a.waitingForDNS[ip] = val.Seq + if aMsg.Type == SOCKADDR { + val.mapDns(aMsg) } val.AddMessage(aMsg) + + // mark if we don't have dns yet + if val.gotSaddr && !val.gotDNS { + ip, _ := val.mapDns(aMsg) + a.waitingForDNS[ip] = val.Seq + } } else { // Create a new AuditMessageGroup a.msgs[aMsg.Seq] = NewAuditMessageGroup(aMsg) @@ -106,15 +110,6 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.flushOld() } -func (a *AuditMarshaller) getDns(val *AuditMessageGroup) (ip string, host []byte) { - for _, msg := range val.Msgs { - if msg.Type == SOCKADDR { - ip, host = val.mapDns(msg) - } - } - return ip, host -} - // Outputs any messages that are old enough // This is because there is no indication of multi message events coming from kaudit func (a *AuditMarshaller) flushOld() { diff --git a/parser.go b/parser.go index 4babdcc..a2aad9a 100644 --- a/parser.go +++ b/parser.go @@ -105,8 +105,6 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { switch am.Type { case EXECVE, CWD: // Don't map uids here - case SOCKADDR: - amg.mapDns(am) case SYSCALL: amg.findSyscall(am) amg.mapUids(am) From 969ef2313ad1d05641964ca83e406afcbc6bd1b3 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 24 Oct 2018 07:44:43 -0700 Subject: [PATCH 35/45] extend marshaller --- audit.go | 13 +- dnstap/dnstap.pb.go | 448 ------------------------------------- dnstap.go => ext_dnstap.go | 16 +- ext_marshaller_dnstap.go | 66 ++++++ marshaller.go | 24 +- 5 files changed, 88 insertions(+), 479 deletions(-) delete mode 100644 dnstap/dnstap.pb.go rename dnstap.go => ext_dnstap.go (87%) create mode 100644 ext_marshaller_dnstap.go diff --git a/audit.go b/audit.go index a8f9916..15d8ad0 100644 --- a/audit.go +++ b/audit.go @@ -363,6 +363,8 @@ func main() { l.Printf("Started processing events in the range [%d, %d]\n", config.GetInt("events.min"), config.GetInt("events.max")) + var dnstapClient *DnsTapClient + if dnstapSckt != "" { cacheCfg := bigcache.Config{ Shards: 256, @@ -378,8 +380,9 @@ func main() { el.Fatal(cacheInitErr) } - dnstapClient, err := NewDnsTapClient(dnstapSckt, marshaller) - //dnstapClient, err := NewDnsTapClient(dnstapSckt) + DnsMarshaller := NewDnsAuditMarshaller(marshaller) + + dnstapClient, err = NewDnsTapClient(dnstapSckt, DnsMarshaller) if err != nil { el.Fatal(err) } @@ -399,7 +402,11 @@ func main() { continue } - marshaller.Consume(msg) + if dnstapClient != nil { + dnstapClient.DnsAuditMarshaller.Consume(msg) + } else { + marshaller.Consume(msg) + } } } diff --git a/dnstap/dnstap.pb.go b/dnstap/dnstap.pb.go deleted file mode 100644 index 43b5fd1..0000000 --- a/dnstap/dnstap.pb.go +++ /dev/null @@ -1,448 +0,0 @@ -// Code generated by protoc-gen-go. -// source: dnstap.proto -// DO NOT EDIT! - -/* -Package dnstap is a generated protocol buffer package. - -It is generated from these files: - dnstap.proto - -It has these top-level messages: - Dnstap - Message -*/ -package dnstap - -import proto "github.com/golang/protobuf/proto" -import json "encoding/json" -import math "math" - -// Reference proto, json, and math imports to suppress error if they are not otherwise used. -var _ = proto.Marshal -var _ = &json.SyntaxError{} -var _ = math.Inf - -// SocketFamily: the network protocol family of a socket. This specifies how -// to interpret "network address" fields. -type SocketFamily int32 - -const ( - SocketFamily_INET SocketFamily = 1 - SocketFamily_INET6 SocketFamily = 2 -) - -var SocketFamily_name = map[int32]string{ - 1: "INET", - 2: "INET6", -} -var SocketFamily_value = map[string]int32{ - "INET": 1, - "INET6": 2, -} - -func (x SocketFamily) Enum() *SocketFamily { - p := new(SocketFamily) - *p = x - return p -} -func (x SocketFamily) String() string { - return proto.EnumName(SocketFamily_name, int32(x)) -} -func (x *SocketFamily) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(SocketFamily_value, data, "SocketFamily") - if err != nil { - return err - } - *x = SocketFamily(value) - return nil -} - -// SocketProtocol: the transport protocol of a socket. This specifies how to -// interpret "transport port" fields. -type SocketProtocol int32 - -const ( - SocketProtocol_UDP SocketProtocol = 1 - SocketProtocol_TCP SocketProtocol = 2 -) - -var SocketProtocol_name = map[int32]string{ - 1: "UDP", - 2: "TCP", -} -var SocketProtocol_value = map[string]int32{ - "UDP": 1, - "TCP": 2, -} - -func (x SocketProtocol) Enum() *SocketProtocol { - p := new(SocketProtocol) - *p = x - return p -} -func (x SocketProtocol) String() string { - return proto.EnumName(SocketProtocol_name, int32(x)) -} -func (x *SocketProtocol) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(SocketProtocol_value, data, "SocketProtocol") - if err != nil { - return err - } - *x = SocketProtocol(value) - return nil -} - -// Identifies which field below is filled in. -type Dnstap_Type int32 - -const ( - Dnstap_MESSAGE Dnstap_Type = 1 -) - -var Dnstap_Type_name = map[int32]string{ - 1: "MESSAGE", -} -var Dnstap_Type_value = map[string]int32{ - "MESSAGE": 1, -} - -func (x Dnstap_Type) Enum() *Dnstap_Type { - p := new(Dnstap_Type) - *p = x - return p -} -func (x Dnstap_Type) String() string { - return proto.EnumName(Dnstap_Type_name, int32(x)) -} -func (x *Dnstap_Type) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Dnstap_Type_value, data, "Dnstap_Type") - if err != nil { - return err - } - *x = Dnstap_Type(value) - return nil -} - -type Message_Type int32 - -const ( - // AUTH_QUERY is a DNS query message received from a resolver by an - // authoritative name server, from the perspective of the authorative - // name server. - Message_AUTH_QUERY Message_Type = 1 - // AUTH_RESPONSE is a DNS response message sent from an authoritative - // name server to a resolver, from the perspective of the authoritative - // name server. - Message_AUTH_RESPONSE Message_Type = 2 - // RESOLVER_QUERY is a DNS query message sent from a resolver to an - // authoritative name server, from the perspective of the resolver. - // Resolvers typically clear the RD (recursion desired) bit when - // sending queries. - Message_RESOLVER_QUERY Message_Type = 3 - // RESOLVER_RESPONSE is a DNS response message received from an - // authoritative name server by a resolver, from the perspective of - // the resolver. - Message_RESOLVER_RESPONSE Message_Type = 4 - // CLIENT_QUERY is a DNS query message sent from a client to a DNS - // server which is expected to perform further recursion, from the - // perspective of the DNS server. The client may be a stub resolver or - // forwarder or some other type of software which typically sets the RD - // (recursion desired) bit when querying the DNS server. The DNS server - // may be a simple forwarding proxy or it may be a full recursive - // resolver. - Message_CLIENT_QUERY Message_Type = 5 - // CLIENT_RESPONSE is a DNS response message sent from a DNS server to - // a client, from the perspective of the DNS server. The DNS server - // typically sets the RA (recursion available) bit when responding. - Message_CLIENT_RESPONSE Message_Type = 6 - // FORWARDER_QUERY is a DNS query message sent from a downstream DNS - // server to an upstream DNS server which is expected to perform - // further recursion, from the perspective of the downstream DNS - // server. - Message_FORWARDER_QUERY Message_Type = 7 - // FORWARDER_RESPONSE is a DNS response message sent from an upstream - // DNS server performing recursion to a downstream DNS server, from the - // perspective of the downstream DNS server. - Message_FORWARDER_RESPONSE Message_Type = 8 - // STUB_QUERY is a DNS query message sent from a stub resolver to a DNS - // server, from the perspective of the stub resolver. - Message_STUB_QUERY Message_Type = 9 - // STUB_RESPONSE is a DNS response message sent from a DNS server to a - // stub resolver, from the perspective of the stub resolver. - Message_STUB_RESPONSE Message_Type = 10 - // TOOL_QUERY is a DNS query message sent from a DNS software tool to a - // DNS server, from the perspective of the tool. - Message_TOOL_QUERY Message_Type = 11 - // TOOL_RESPONSE is a DNS response message received by a DNS software - // tool from a DNS server, from the perspective of the tool. - Message_TOOL_RESPONSE Message_Type = 12 -) - -var Message_Type_name = map[int32]string{ - 1: "AUTH_QUERY", - 2: "AUTH_RESPONSE", - 3: "RESOLVER_QUERY", - 4: "RESOLVER_RESPONSE", - 5: "CLIENT_QUERY", - 6: "CLIENT_RESPONSE", - 7: "FORWARDER_QUERY", - 8: "FORWARDER_RESPONSE", - 9: "STUB_QUERY", - 10: "STUB_RESPONSE", - 11: "TOOL_QUERY", - 12: "TOOL_RESPONSE", -} -var Message_Type_value = map[string]int32{ - "AUTH_QUERY": 1, - "AUTH_RESPONSE": 2, - "RESOLVER_QUERY": 3, - "RESOLVER_RESPONSE": 4, - "CLIENT_QUERY": 5, - "CLIENT_RESPONSE": 6, - "FORWARDER_QUERY": 7, - "FORWARDER_RESPONSE": 8, - "STUB_QUERY": 9, - "STUB_RESPONSE": 10, - "TOOL_QUERY": 11, - "TOOL_RESPONSE": 12, -} - -func (x Message_Type) Enum() *Message_Type { - p := new(Message_Type) - *p = x - return p -} -func (x Message_Type) String() string { - return proto.EnumName(Message_Type_name, int32(x)) -} -func (x *Message_Type) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(Message_Type_value, data, "Message_Type") - if err != nil { - return err - } - *x = Message_Type(value) - return nil -} - -// "Dnstap": this is the top-level dnstap type, which is a "union" type that -// contains other kinds of dnstap payloads, although currently only one type -// of dnstap payload is defined. -// See: https://developers.google.com/protocol-buffers/docs/techniques#union -type Dnstap struct { - // DNS server identity. - // If enabled, this is the identity string of the DNS server which generated - // this message. Typically this would be the same string as returned by an - // "NSID" (RFC 5001) query. - Identity []byte `protobuf:"bytes,1,opt,name=identity" json:"identity,omitempty"` - // DNS server version. - // If enabled, this is the version string of the DNS server which generated - // this message. Typically this would be the same string as returned by a - // "version.bind" query. - Version []byte `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"` - // Extra data for this payload. - // This field can be used for adding an arbitrary byte-string annotation to - // the payload. No encoding or interpretation is applied or enforced. - Extra []byte `protobuf:"bytes,3,opt,name=extra" json:"extra,omitempty"` - Type *Dnstap_Type `protobuf:"varint,15,req,name=type,enum=dnstap.Dnstap_Type" json:"type,omitempty"` - // One of the following will be filled in. - Message *Message `protobuf:"bytes,14,opt,name=message" json:"message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Dnstap) Reset() { *m = Dnstap{} } -func (m *Dnstap) String() string { return proto.CompactTextString(m) } -func (*Dnstap) ProtoMessage() {} - -func (m *Dnstap) GetIdentity() []byte { - if m != nil { - return m.Identity - } - return nil -} - -func (m *Dnstap) GetVersion() []byte { - if m != nil { - return m.Version - } - return nil -} - -func (m *Dnstap) GetExtra() []byte { - if m != nil { - return m.Extra - } - return nil -} - -func (m *Dnstap) GetType() Dnstap_Type { - if m != nil && m.Type != nil { - return *m.Type - } - return Dnstap_MESSAGE -} - -func (m *Dnstap) GetMessage() *Message { - if m != nil { - return m.Message - } - return nil -} - -// Message: a wire-format (RFC 1035 section 4) DNS message and associated -// metadata. Applications generating "Message" payloads should follow -// certain requirements based on the MessageType, see below. -type Message struct { - // One of the Type values described above. - Type *Message_Type `protobuf:"varint,1,req,name=type,enum=dnstap.Message_Type" json:"type,omitempty"` - // One of the SocketFamily values described above. - SocketFamily *SocketFamily `protobuf:"varint,2,opt,name=socket_family,enum=dnstap.SocketFamily" json:"socket_family,omitempty"` - // One of the SocketProtocol values described above. - SocketProtocol *SocketProtocol `protobuf:"varint,3,opt,name=socket_protocol,enum=dnstap.SocketProtocol" json:"socket_protocol,omitempty"` - // The network address of the message initiator. - // For SocketFamily INET, this field is 4 octets (IPv4 address). - // For SocketFamily INET6, this field is 16 octets (IPv6 address). - QueryAddress []byte `protobuf:"bytes,4,opt,name=query_address" json:"query_address,omitempty"` - // The network address of the message responder. - // For SocketFamily INET, this field is 4 octets (IPv4 address). - // For SocketFamily INET6, this field is 16 octets (IPv6 address). - ResponseAddress []byte `protobuf:"bytes,5,opt,name=response_address" json:"response_address,omitempty"` - // The transport port of the message initiator. - // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. - QueryPort *uint32 `protobuf:"varint,6,opt,name=query_port" json:"query_port,omitempty"` - // The transport port of the message responder. - // This is a 16-bit UDP or TCP port number, depending on SocketProtocol. - ResponsePort *uint32 `protobuf:"varint,7,opt,name=response_port" json:"response_port,omitempty"` - // The time at which the DNS query message was sent or received, depending - // on whether this is an AUTH_QUERY, RESOLVER_QUERY, or CLIENT_QUERY. - // This is the number of seconds since the UNIX epoch. - QueryTimeSec *uint64 `protobuf:"varint,8,opt,name=query_time_sec" json:"query_time_sec,omitempty"` - // The time at which the DNS query message was sent or received. - // This is the seconds fraction, expressed as a count of nanoseconds. - QueryTimeNsec *uint32 `protobuf:"fixed32,9,opt,name=query_time_nsec" json:"query_time_nsec,omitempty"` - // The initiator's original wire-format DNS query message, verbatim. - QueryMessage []byte `protobuf:"bytes,10,opt,name=query_message" json:"query_message,omitempty"` - // The "zone" or "bailiwick" pertaining to the DNS query message. - // This is a wire-format DNS domain name. - QueryZone []byte `protobuf:"bytes,11,opt,name=query_zone" json:"query_zone,omitempty"` - // The time at which the DNS response message was sent or received, - // depending on whether this is an AUTH_RESPONSE, RESOLVER_RESPONSE, or - // CLIENT_RESPONSE. - // This is the number of seconds since the UNIX epoch. - ResponseTimeSec *uint64 `protobuf:"varint,12,opt,name=response_time_sec" json:"response_time_sec,omitempty"` - // The time at which the DNS response message was sent or received. - // This is the seconds fraction, expressed as a count of nanoseconds. - ResponseTimeNsec *uint32 `protobuf:"fixed32,13,opt,name=response_time_nsec" json:"response_time_nsec,omitempty"` - // The responder's original wire-format DNS response message, verbatim. - ResponseMessage []byte `protobuf:"bytes,14,opt,name=response_message" json:"response_message,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Message) Reset() { *m = Message{} } -func (m *Message) String() string { return proto.CompactTextString(m) } -func (*Message) ProtoMessage() {} - -func (m *Message) GetType() Message_Type { - if m != nil && m.Type != nil { - return *m.Type - } - return Message_AUTH_QUERY -} - -func (m *Message) GetSocketFamily() SocketFamily { - if m != nil && m.SocketFamily != nil { - return *m.SocketFamily - } - return SocketFamily_INET -} - -func (m *Message) GetSocketProtocol() SocketProtocol { - if m != nil && m.SocketProtocol != nil { - return *m.SocketProtocol - } - return SocketProtocol_UDP -} - -func (m *Message) GetQueryAddress() []byte { - if m != nil { - return m.QueryAddress - } - return nil -} - -func (m *Message) GetResponseAddress() []byte { - if m != nil { - return m.ResponseAddress - } - return nil -} - -func (m *Message) GetQueryPort() uint32 { - if m != nil && m.QueryPort != nil { - return *m.QueryPort - } - return 0 -} - -func (m *Message) GetResponsePort() uint32 { - if m != nil && m.ResponsePort != nil { - return *m.ResponsePort - } - return 0 -} - -func (m *Message) GetQueryTimeSec() uint64 { - if m != nil && m.QueryTimeSec != nil { - return *m.QueryTimeSec - } - return 0 -} - -func (m *Message) GetQueryTimeNsec() uint32 { - if m != nil && m.QueryTimeNsec != nil { - return *m.QueryTimeNsec - } - return 0 -} - -func (m *Message) GetQueryMessage() []byte { - if m != nil { - return m.QueryMessage - } - return nil -} - -func (m *Message) GetQueryZone() []byte { - if m != nil { - return m.QueryZone - } - return nil -} - -func (m *Message) GetResponseTimeSec() uint64 { - if m != nil && m.ResponseTimeSec != nil { - return *m.ResponseTimeSec - } - return 0 -} - -func (m *Message) GetResponseTimeNsec() uint32 { - if m != nil && m.ResponseTimeNsec != nil { - return *m.ResponseTimeNsec - } - return 0 -} - -func (m *Message) GetResponseMessage() []byte { - if m != nil { - return m.ResponseMessage - } - return nil -} - -func init() { - proto.RegisterEnum("dnstap.SocketFamily", SocketFamily_name, SocketFamily_value) - proto.RegisterEnum("dnstap.SocketProtocol", SocketProtocol_name, SocketProtocol_value) - proto.RegisterEnum("dnstap.Dnstap_Type", Dnstap_Type_name, Dnstap_Type_value) - proto.RegisterEnum("dnstap.Message_Type", Message_Type_name, Message_Type_value) -} diff --git a/dnstap.go b/ext_dnstap.go similarity index 87% rename from dnstap.go rename to ext_dnstap.go index c49fb1b..acfb31c 100644 --- a/dnstap.go +++ b/ext_dnstap.go @@ -6,8 +6,6 @@ import ( "os" "strings" - // "time" - "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" @@ -16,10 +14,10 @@ import ( type DnsTapClient struct { Listener net.Listener - AuditMarshaller *AuditMarshaller + DnsAuditMarshaller *DnsAuditMarshaller } -func NewDnsTapClient(socket string, am *AuditMarshaller) (*DnsTapClient, error) { +func NewDnsTapClient(socket string, am *DnsAuditMarshaller) (*DnsTapClient, error) { os.Remove(socket) listener, err := net.Listen("unix", socket) if err != nil { @@ -27,7 +25,7 @@ func NewDnsTapClient(socket string, am *AuditMarshaller) (*DnsTapClient, error) } d := &DnsTapClient{ Listener: listener, - AuditMarshaller: am, + DnsAuditMarshaller: am, } l.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil @@ -84,14 +82,14 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { ipv4 := m.Answer[i].(*dns.A).A.String() c.Set(ipv4, []byte(host)) // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) - if seq, ok := d.AuditMarshaller.waitingForDNS[ipv4]; ok { - if msg, ok := d.AuditMarshaller.msgs[seq]; ok { + if seq, ok := d.DnsAuditMarshaller.waitingForDNS[ipv4]; ok { + if msg, ok := d.DnsAuditMarshaller.msgs[seq]; ok { if !msg.gotDNS && msg.gotSaddr { getDns(msg) } - d.AuditMarshaller.completeMessage(seq) + d.DnsAuditMarshaller.completeMessage(seq) } - delete(d.AuditMarshaller.waitingForDNS, ipv4) + delete(d.DnsAuditMarshaller.waitingForDNS, ipv4) } case dns.TypeAAAA: ipv6 := m.Answer[i].(*dns.AAAA).AAAA.String() diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go new file mode 100644 index 0000000..0c7c7c9 --- /dev/null +++ b/ext_marshaller_dnstap.go @@ -0,0 +1,66 @@ +package main + +import ( + "syscall" +) + +type DnsAuditMarshaller struct { + *AuditMarshaller + waitingForDNS map[string]int +} + +func NewDnsAuditMarshaller(am *AuditMarshaller) *DnsAuditMarshaller { + dam := &DnsAuditMarshaller{ + am, + make(map[string]int), + } + + return dam +} + +// Ingests a netlink message and likely prepares it to be logged +func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { + aMsg := NewAuditMessage(nlMsg) + + if aMsg.Seq == 0 { + // We got an invalid audit message, return the current message and reset + a.flushOld() + return + } + + if a.trackMessages { + a.detectMissing(aMsg.Seq) + } + + if nlMsg.Header.Type < a.eventMin || nlMsg.Header.Type > a.eventMax { + // Drop all audit messages that aren't things we care about or end a multi packet event + a.flushOld() + return + } + + val, ok := a.msgs[aMsg.Seq] + + if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr) { + a.completeMessage(aMsg.Seq) + return + } + + if ok { + if aMsg.Type == SOCKADDR { + val.mapDns(aMsg) + } + + val.AddMessage(aMsg) + + // mark if we don't have dns yet + if val.gotSaddr && !val.gotDNS { + ip, _ := val.mapDns(aMsg) + a.waitingForDNS[ip] = val.Seq + } + } else { + // Create a new AuditMessageGroup + a.msgs[aMsg.Seq] = NewAuditMessageGroup(aMsg) + } + + a.flushOld() +} diff --git a/marshaller.go b/marshaller.go index 3ea1e8c..9047a64 100644 --- a/marshaller.go +++ b/marshaller.go @@ -24,7 +24,6 @@ type AuditMarshaller struct { maxOutOfOrder int attempts int filters map[string]map[uint16][]*regexp.Regexp // { syscall: { mtype: [regexp, ...] } } - waitingForDNS map[string]int } type AuditFilter struct { @@ -45,7 +44,6 @@ func NewAuditMarshaller(w *AuditWriter, eventMin uint16, eventMax uint16, trackM logOutOfOrder: logOOO, maxOutOfOrder: maxOOO, filters: make(map[string]map[uint16][]*regexp.Regexp), - waitingForDNS: make(map[string]int), } for _, filter := range filters { @@ -81,27 +79,15 @@ func (a *AuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { // Drop all audit messages that aren't things we care about or end a multi packet event a.flushOld() return - } - - val, ok := a.msgs[aMsg.Seq] - - if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr) { + } else if nlMsg.Header.Type == EVENT_EOE { + // This is end of event msg, flush the msg with that sequence and discard this one a.completeMessage(aMsg.Seq) return } - if ok { - if aMsg.Type == SOCKADDR { - val.mapDns(aMsg) - } - + if val, ok := a.msgs[aMsg.Seq]; ok { + // Use the original AuditMessageGroup if we have one val.AddMessage(aMsg) - - // mark if we don't have dns yet - if val.gotSaddr && !val.gotDNS { - ip, _ := val.mapDns(aMsg) - a.waitingForDNS[ip] = val.Seq - } } else { // Create a new AuditMessageGroup a.msgs[aMsg.Seq] = NewAuditMessageGroup(aMsg) @@ -116,7 +102,7 @@ func (a *AuditMarshaller) flushOld() { now := time.Now() for seq, msg := range a.msgs { if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { - a.waitingForDNS = make(map[string]int) + // a.waitingForDNS = make(map[string]int) a.completeMessage(seq) } } From 9e6101748f75fa655db2da8a9136fb8991ccfb35 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Sat, 27 Oct 2018 12:36:44 -0700 Subject: [PATCH 36/45] why does this not get the first lookup --- audit.go | 18 ------ ext_dnstap.go | 19 +++--- ext_marshaller_dnstap.go | 126 ++++++++++++++++++++++++++++++++++++--- parser.go | 55 ----------------- 4 files changed, 128 insertions(+), 90 deletions(-) diff --git a/audit.go b/audit.go index 15d8ad0..882f7a7 100644 --- a/audit.go +++ b/audit.go @@ -14,15 +14,10 @@ import ( "strconv" "strings" "syscall" - "time" - "github.com/allegro/bigcache" "github.com/spf13/viper" ) -var c *bigcache.BigCache -var cacheInitErr error - var l = log.New(os.Stdout, "", 0) var el = log.New(os.Stderr, "", 0) @@ -366,19 +361,6 @@ func main() { var dnstapClient *DnsTapClient if dnstapSckt != "" { - cacheCfg := bigcache.Config{ - Shards: 256, - LifeWindow: time.Second * 300, - MaxEntriesInWindow: 1024, - MaxEntrySize: 96, - HardMaxCacheSize: 10, - } - - c, cacheInitErr = bigcache.NewBigCache(cacheCfg) - - if cacheInitErr != nil { - el.Fatal(cacheInitErr) - } DnsMarshaller := NewDnsAuditMarshaller(marshaller) diff --git a/ext_dnstap.go b/ext_dnstap.go index acfb31c..fe06443 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -13,7 +13,7 @@ import ( ) type DnsTapClient struct { - Listener net.Listener + Listener net.Listener DnsAuditMarshaller *DnsAuditMarshaller } @@ -24,7 +24,7 @@ func NewDnsTapClient(socket string, am *DnsAuditMarshaller) (*DnsTapClient, erro return nil, fmt.Errorf("Listen error: %s", err) } d := &DnsTapClient{ - Listener: listener, + Listener: listener, DnsAuditMarshaller: am, } l.Printf("Started dnstap listener, opened input socket: %s", socket) @@ -80,12 +80,12 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { switch m.Answer[i].Header().Rrtype { case dns.TypeA: ipv4 := m.Answer[i].(*dns.A).A.String() - c.Set(ipv4, []byte(host)) + d.DnsAuditMarshaller.cache.Set(ipv4, []byte(host)) // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) if seq, ok := d.DnsAuditMarshaller.waitingForDNS[ipv4]; ok { if msg, ok := d.DnsAuditMarshaller.msgs[seq]; ok { - if !msg.gotDNS && msg.gotSaddr { - getDns(msg) + if !d.DnsAuditMarshaller.gotDNS[seq] && d.DnsAuditMarshaller.gotSaddr[seq] { + d.DnsAuditMarshaller.getDNS(msg) } d.DnsAuditMarshaller.completeMessage(seq) } @@ -93,11 +93,10 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { } case dns.TypeAAAA: ipv6 := m.Answer[i].(*dns.AAAA).AAAA.String() - c.Set(ipv6, []byte(host)) - //el.Printf("Setting ipv6 for %s -> %s @ %v", host, ipv6, time.Now().Unix()) + d.DnsAuditMarshaller.cache.Set(ipv6, []byte(host)) case dns.TypeCNAME: cname := m.Answer[i].(*dns.CNAME).Target - c.Set(cname, []byte(host)) + d.DnsAuditMarshaller.cache.Set(cname, []byte(host)) //el.Printf("Setting cname for %s -> %s @ %v", host, cname, time.Now().Unix()) } @@ -105,10 +104,10 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { } } -func getDns(val *AuditMessageGroup) (ip string, host []byte) { +func (dnsAm *DnsAuditMarshaller) getDNS(val *AuditMessageGroup) (ip string, host []byte) { for _, msg := range val.Msgs { if msg.Type == SOCKADDR { - ip, host = val.mapDns(msg) + ip, host = dnsAm.mapDns(msg) } } return ip, host diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index 0c7c7c9..cd51428 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -1,21 +1,49 @@ package main import ( + "encoding/hex" + "net" + "strconv" "syscall" + "time" + + "strings" + + "github.com/allegro/bigcache" ) type DnsAuditMarshaller struct { *AuditMarshaller waitingForDNS map[string]int + cache *bigcache.BigCache + gotSaddr map[int]bool + gotDNS map[int]bool } func NewDnsAuditMarshaller(am *AuditMarshaller) *DnsAuditMarshaller { - dam := &DnsAuditMarshaller{ + cacheCfg := bigcache.Config{ + Shards: 256, + LifeWindow: time.Second * 300, + MaxEntriesInWindow: 1024, + MaxEntrySize: 96, + HardMaxCacheSize: 10, + } + + c, cacheInitErr := bigcache.NewBigCache(cacheCfg) + + if cacheInitErr != nil { + el.Fatal(cacheInitErr) + } + + dnsAm := &DnsAuditMarshaller{ am, make(map[string]int), + c, + make(map[int]bool), + make(map[int]bool), } - return dam + return dnsAm } // Ingests a netlink message and likely prepares it to be logged @@ -40,21 +68,21 @@ func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val, ok := a.msgs[aMsg.Seq] - if ok && nlMsg.Header.Type == EVENT_EOE && (val.gotDNS || !val.gotSaddr) { + if ok && nlMsg.Header.Type == EVENT_EOE && (a.gotDNS[aMsg.Seq] || !a.gotSaddr[aMsg.Seq]) { a.completeMessage(aMsg.Seq) return } if ok { if aMsg.Type == SOCKADDR { - val.mapDns(aMsg) + a.mapDns(aMsg) } val.AddMessage(aMsg) - // mark if we don't have dns yet - if val.gotSaddr && !val.gotDNS { - ip, _ := val.mapDns(aMsg) + // Mark if we don't have dns yet + if a.gotSaddr[aMsg.Seq] && !a.gotDNS[aMsg.Seq] { + ip, _ := a.mapDns(aMsg) a.waitingForDNS[ip] = val.Seq } } else { @@ -64,3 +92,87 @@ func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.flushOld() } + +// Find all `saddr=` occurrences in a message and do a lookup +func (dnsAm *DnsAuditMarshaller) mapDns(am *AuditMessage) (ip string, host []byte) { + data := am.Data + start := 0 + end := 0 + + if start = strings.Index(data, "saddr="); start < 0 { + return + } + + // Progress the start point beyond the = sign + start += 6 + if end = strings.IndexByte(data[start:], spaceChar); end < 0 { + end = len(data) - start + if end > SOCKADDR_LENGTH { + return + } + } + + saddr := data[start : start+end] + + dnsAm.gotSaddr[am.Seq] = true + + var err error + + ip = parseAddr(saddr) + port := parsePortIpv4(saddr) + + dnsAm.msgs[am.Seq].DnsMap["ip"] = ip + dnsAm.msgs[am.Seq].DnsMap["port"] = strconv.FormatInt(port, 10) + + host, err = dnsAm.cache.Get(ip) + if err == nil { + dnsAm.gotDNS[am.Seq] = true + dnsAm.msgs[am.Seq].DnsMap["record"] = string(host) + } + return +} + +func parseFamily(saddr string) int64 { + a, err := strconv.ParseInt(saddr[0:2], 16, 32) + if err != nil { + el.Println(err) + } + + b, err := strconv.ParseInt(saddr[2:4], 16, 32) + if err != nil { + el.Println(err) + } + + return a + 256*b + +} + +func parsePortIpv4(saddr string) int64 { + a, err := strconv.ParseInt(saddr[4:6], 16, 32) + if err != nil { + el.Println(err) + } + + b, err := strconv.ParseInt(saddr[6:8], 16, 32) + if err != nil { + el.Println(err) + } + + return a*256 + b +} + +func parseAddr(saddr string) (addr string) { + family := parseFamily(saddr) + //el.Println("FAM:", family) + + switch family { + case 2: + b, err := hex.DecodeString(saddr[8:16]) + if err != nil { + el.Printf("unable to decode hex to bytes: %s", err) + } + addr = net.IP(b).String() + } + + return addr +} diff --git a/parser.go b/parser.go index a2aad9a..0a2f4e0 100644 --- a/parser.go +++ b/parser.go @@ -2,10 +2,7 @@ package main import ( "bytes" - "encoding/hex" - // "fmt" - "net" "os/user" "strconv" "strings" @@ -45,8 +42,6 @@ type AuditMessageGroup struct { UidMap map[string]string `json:"uid_map"` DnsMap map[string]string `json:"dnstap"` Syscall string `json:"-"` - gotSaddr bool - gotDNS bool } // Creates a new message group from the details parsed from the message @@ -113,56 +108,6 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { } } -// Find all `saddr=` occurrences in a message and do a lookup -func (amg *AuditMessageGroup) mapDns(am *AuditMessage) (ip string, host []byte) { - data := am.Data - start := 0 - end := 0 - - if start = strings.Index(data, "saddr="); start < 0 { - return - } - - // Progress the start point beyond the = sign - start += 6 - if end = strings.IndexByte(data[start:], spaceChar); end < 0 { - end = len(data) - start - if end > SOCKADDR_LENGTH { - return - } - } - - saddr := data[start : start+end] - - amg.gotSaddr = true - - var err error - - ip = parseAddr(saddr) - - host, err = c.Get(ip) - if err == nil { - amg.gotDNS = true - amg.DnsMap[ip] = string(host) - //amg.DnsMap["time"] = fmt.Sprintf("%v", time.Now().Unix()) - } - return -} - -func parseAddr(saddr string) (addr string) { - switch family := saddr[0:4]; family { - // 0200: ipv4 - case "0200": - b, err := hex.DecodeString(saddr[8:16]) - if err != nil { - el.Printf("unable to decode hex to bytes: %s", err) - } - addr = net.IP(b).String() - } - - return addr -} - // Find all `uid=` occurrences in a message and adds the username to the UidMap object func (amg *AuditMessageGroup) mapUids(am *AuditMessage) { data := am.Data From 24e49b2f1a8ebc60f37e7c4a06926374dbce483d Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Sun, 28 Oct 2018 12:47:42 -0700 Subject: [PATCH 37/45] working with removed 1320 --- ext_dnstap.go | 5 ++-- ext_marshaller_dnstap.go | 61 +++++++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/ext_dnstap.go b/ext_dnstap.go index fe06443..18d04a7 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -6,6 +6,8 @@ import ( "os" "strings" + // "time" + "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" @@ -81,10 +83,9 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { case dns.TypeA: ipv4 := m.Answer[i].(*dns.A).A.String() d.DnsAuditMarshaller.cache.Set(ipv4, []byte(host)) - // el.Printf("Setting ipv4 for %s -> %s @ %v", host, ipv4, time.Now().Unix()) if seq, ok := d.DnsAuditMarshaller.waitingForDNS[ipv4]; ok { if msg, ok := d.DnsAuditMarshaller.msgs[seq]; ok { - if !d.DnsAuditMarshaller.gotDNS[seq] && d.DnsAuditMarshaller.gotSaddr[seq] { + if !d.DnsAuditMarshaller.GotDNS[seq] && d.DnsAuditMarshaller.GotSaddr[seq] { d.DnsAuditMarshaller.getDNS(msg) } d.DnsAuditMarshaller.completeMessage(seq) diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index cd51428..3a427f4 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -3,6 +3,8 @@ package main import ( "encoding/hex" "net" + + "os" "strconv" "syscall" "time" @@ -16,8 +18,8 @@ type DnsAuditMarshaller struct { *AuditMarshaller waitingForDNS map[string]int cache *bigcache.BigCache - gotSaddr map[int]bool - gotDNS map[int]bool + GotSaddr map[int]bool + GotDNS map[int]bool } func NewDnsAuditMarshaller(am *AuditMarshaller) *DnsAuditMarshaller { @@ -68,7 +70,7 @@ func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val, ok := a.msgs[aMsg.Seq] - if ok && nlMsg.Header.Type == EVENT_EOE && (a.gotDNS[aMsg.Seq] || !a.gotSaddr[aMsg.Seq]) { + if ok && nlMsg.Header.Type == EVENT_EOE && (a.GotDNS[aMsg.Seq] || !a.GotSaddr[aMsg.Seq]) { a.completeMessage(aMsg.Seq) return } @@ -81,10 +83,17 @@ func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { val.AddMessage(aMsg) // Mark if we don't have dns yet - if a.gotSaddr[aMsg.Seq] && !a.gotDNS[aMsg.Seq] { + if a.GotSaddr[aMsg.Seq] && !a.GotDNS[aMsg.Seq] { ip, _ := a.mapDns(aMsg) a.waitingForDNS[ip] = val.Seq } + + for i, m := range val.Msgs { + if m.Type == EVENT_EOE { + val.Msgs = append(val.Msgs[:i], val.Msgs[i+1:]...) + } + } + } else { // Create a new AuditMessageGroup a.msgs[aMsg.Seq] = NewAuditMessageGroup(aMsg) @@ -114,7 +123,7 @@ func (dnsAm *DnsAuditMarshaller) mapDns(am *AuditMessage) (ip string, host []byt saddr := data[start : start+end] - dnsAm.gotSaddr[am.Seq] = true + dnsAm.GotSaddr[am.Seq] = true var err error @@ -123,10 +132,12 @@ func (dnsAm *DnsAuditMarshaller) mapDns(am *AuditMessage) (ip string, host []byt dnsAm.msgs[am.Seq].DnsMap["ip"] = ip dnsAm.msgs[am.Seq].DnsMap["port"] = strconv.FormatInt(port, 10) + //dnsAm.msgs[am.Seq].DnsMap["GotSaddr"] = "true" host, err = dnsAm.cache.Get(ip) if err == nil { - dnsAm.gotDNS[am.Seq] = true + // dnsAm.GotDNS[am.Seq] = true + // dnsAm.msgs[am.Seq].DnsMap["GotDNS"] = "true" dnsAm.msgs[am.Seq].DnsMap["record"] = string(host) } return @@ -163,7 +174,6 @@ func parsePortIpv4(saddr string) int64 { func parseAddr(saddr string) (addr string) { family := parseFamily(saddr) - //el.Println("FAM:", family) switch family { case 2: @@ -176,3 +186,40 @@ func parseAddr(saddr string) (addr string) { return addr } + +func (a *DnsAuditMarshaller) completeMessage(seq int) { + var msg *AuditMessageGroup + var ok bool + + if msg, ok = a.msgs[seq]; !ok { + //TODO: attempted to complete a missing message, log? + return + } + + if a.GotSaddr[seq] && !a.GotDNS[seq] { + a.getDNS(msg) + } + + if a.dropMessage(msg) { + delete(a.msgs, seq) + return + } + + if err := a.writer.Write(msg); err != nil { + el.Println("Failed to write message. Error:", err) + os.Exit(1) + } + + delete(a.msgs, seq) +} + +// Outputs any messages that are old enough +// This is because there is no indication of multi message events coming from kaudit +func (a *DnsAuditMarshaller) flushOld() { + now := time.Now() + for seq, msg := range a.msgs { + if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { + a.completeMessage(seq) + } + } +} From 35d5c8f806db6cbc7befa8a1fc63b82dcbb28e4b Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 29 Oct 2018 06:34:26 -0700 Subject: [PATCH 38/45] don't add msg if its eoe --- ext_marshaller_dnstap.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index 3a427f4..d970747 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -80,18 +80,14 @@ func (a *DnsAuditMarshaller) Consume(nlMsg *syscall.NetlinkMessage) { a.mapDns(aMsg) } - val.AddMessage(aMsg) - // Mark if we don't have dns yet if a.GotSaddr[aMsg.Seq] && !a.GotDNS[aMsg.Seq] { ip, _ := a.mapDns(aMsg) a.waitingForDNS[ip] = val.Seq } - for i, m := range val.Msgs { - if m.Type == EVENT_EOE { - val.Msgs = append(val.Msgs[:i], val.Msgs[i+1:]...) - } + if aMsg.Type != EVENT_EOE { + val.AddMessage(aMsg) } } else { From 900a10150bbc39b84f4706cc61377470d79b0a6c Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 6 Nov 2018 11:25:02 -0800 Subject: [PATCH 39/45] get rid of port, back to ip-->host map --- ext_marshaller_dnstap.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index d970747..30fcd43 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -124,17 +124,10 @@ func (dnsAm *DnsAuditMarshaller) mapDns(am *AuditMessage) (ip string, host []byt var err error ip = parseAddr(saddr) - port := parsePortIpv4(saddr) - - dnsAm.msgs[am.Seq].DnsMap["ip"] = ip - dnsAm.msgs[am.Seq].DnsMap["port"] = strconv.FormatInt(port, 10) - //dnsAm.msgs[am.Seq].DnsMap["GotSaddr"] = "true" host, err = dnsAm.cache.Get(ip) if err == nil { - // dnsAm.GotDNS[am.Seq] = true - // dnsAm.msgs[am.Seq].DnsMap["GotDNS"] = "true" - dnsAm.msgs[am.Seq].DnsMap["record"] = string(host) + dnsAm.msgs[am.Seq].DnsMap[ip] = string(host) } return } From 4f05b807601283cb6c1ec01780525903c6b1b067 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 6 Nov 2018 14:57:45 -0800 Subject: [PATCH 40/45] add options for cache and dnstap enabled --- audit.go | 16 +++++++++++++--- ext_dnstap.go | 3 +-- ext_marshaller_dnstap.go | 10 +--------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/audit.go b/audit.go index 882f7a7..2055a5b 100644 --- a/audit.go +++ b/audit.go @@ -15,6 +15,8 @@ import ( "strings" "syscall" + "github.com/allegro/bigcache" + "github.com/spf13/viper" ) @@ -344,7 +346,7 @@ func main() { el.Fatal(err) } - dnstapSckt := config.GetString("dnstap.socket") + dnstapEnabled := config.GetBool("dnstap.enabled") marshaller := NewAuditMarshaller( writer, @@ -360,9 +362,17 @@ func main() { var dnstapClient *DnsTapClient - if dnstapSckt != "" { + if dnstapEnabled { + dnstapSckt := config.GetString("dnstap.socket") + cacheCfg := bigcache.Config{ + LifeWindow: config.GetDuration("dnstap.record_ttl"), + HardMaxCacheSize: config.GetInt("dnstap.max_cache_size"), + MaxEntrySize: 96, + MaxEntriesInWindow: 1024, + Shards: 256, + } - DnsMarshaller := NewDnsAuditMarshaller(marshaller) + DnsMarshaller := NewDnsAuditMarshaller(marshaller, cacheCfg) dnstapClient, err = NewDnsTapClient(dnstapSckt, DnsMarshaller) if err != nil { diff --git a/ext_dnstap.go b/ext_dnstap.go index 18d04a7..2fcf69a 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -6,8 +6,6 @@ import ( "os" "strings" - // "time" - "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" @@ -25,6 +23,7 @@ func NewDnsTapClient(socket string, am *DnsAuditMarshaller) (*DnsTapClient, erro if err != nil { return nil, fmt.Errorf("Listen error: %s", err) } + d := &DnsTapClient{ Listener: listener, DnsAuditMarshaller: am, diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index 30fcd43..a39b2df 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -22,15 +22,7 @@ type DnsAuditMarshaller struct { GotDNS map[int]bool } -func NewDnsAuditMarshaller(am *AuditMarshaller) *DnsAuditMarshaller { - cacheCfg := bigcache.Config{ - Shards: 256, - LifeWindow: time.Second * 300, - MaxEntriesInWindow: 1024, - MaxEntrySize: 96, - HardMaxCacheSize: 10, - } - +func NewDnsAuditMarshaller(am *AuditMarshaller, cacheCfg bigcache.Config) *DnsAuditMarshaller { c, cacheInitErr := bigcache.NewBigCache(cacheCfg) if cacheInitErr != nil { From 827394e267aa062b6c9cb406f6db5099d74dbd56 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Tue, 6 Nov 2018 15:03:39 -0800 Subject: [PATCH 41/45] update go-audit config --- go-audit.yaml.example | 5 ++++- parser.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/go-audit.yaml.example b/go-audit.yaml.example index 8d02369..4d02e6f 100644 --- a/go-audit.yaml.example +++ b/go-audit.yaml.example @@ -7,8 +7,11 @@ socket_buffer: receive: 16384 # Configure dnstap socket path if available -dnstap: +dnstap: + enabled: true socket: /var/run/dnstap.sock + record_ttl: 300s + max_cache_size: 10 # in mb events: # Minimum event type to capture, default 1300 diff --git a/parser.go b/parser.go index 0a2f4e0..c12da7f 100644 --- a/parser.go +++ b/parser.go @@ -98,7 +98,7 @@ func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) { amg.Msgs = append(amg.Msgs, am) //TODO: need to find more message types that won't contain uids, also make these constants switch am.Type { - case EXECVE, CWD: + case EXECVE, CWD, SOCKADDR: // Don't map uids here case SYSCALL: amg.findSyscall(am) From ca0d5c68ce955d2b8bf22f760f97bbcf2679e3b3 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Wed, 7 Nov 2018 10:14:21 -0800 Subject: [PATCH 42/45] set option for socket owner --- audit.go | 3 +-- ext_dnstap.go | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/audit.go b/audit.go index 2055a5b..9f2a383 100644 --- a/audit.go +++ b/audit.go @@ -363,7 +363,6 @@ func main() { var dnstapClient *DnsTapClient if dnstapEnabled { - dnstapSckt := config.GetString("dnstap.socket") cacheCfg := bigcache.Config{ LifeWindow: config.GetDuration("dnstap.record_ttl"), HardMaxCacheSize: config.GetInt("dnstap.max_cache_size"), @@ -374,7 +373,7 @@ func main() { DnsMarshaller := NewDnsAuditMarshaller(marshaller, cacheCfg) - dnstapClient, err = NewDnsTapClient(dnstapSckt, DnsMarshaller) + dnstapClient, err = NewDnsTapClient(config, DnsMarshaller) if err != nil { el.Fatal(err) } diff --git a/ext_dnstap.go b/ext_dnstap.go index 2fcf69a..f354d46 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -4,12 +4,15 @@ import ( "fmt" "net" "os" + "os/user" + "strconv" "strings" "github.com/dnstap/golang-dnstap" "github.com/farsightsec/golang-framestream" "github.com/golang/protobuf/proto" "github.com/miekg/dns" + "github.com/spf13/viper" ) type DnsTapClient struct { @@ -17,18 +20,46 @@ type DnsTapClient struct { DnsAuditMarshaller *DnsAuditMarshaller } -func NewDnsTapClient(socket string, am *DnsAuditMarshaller) (*DnsTapClient, error) { +func NewDnsTapClient(config *viper.Viper, am *DnsAuditMarshaller) (*DnsTapClient, error) { + socket := config.GetString("dnstap.socket") os.Remove(socket) + listener, err := net.Listen("unix", socket) if err != nil { return nil, fmt.Errorf("Listen error: %s", err) } + socketOwner := config.GetString("dnstap.socket_owner") + + u, err := user.Lookup(socketOwner) + if err != nil { + return nil, fmt.Errorf("Could not find uid for user %s. Error: %s", socketOwner, err) + } + + uid, err := strconv.ParseInt(u.Uid, 10, 32) + if err != nil { + return nil, fmt.Errorf("Found uid could not be parsed. Error: %s", err) + } + + g, err := user.LookupGroup(socketOwner) + if err != nil { + return nil, fmt.Errorf("Could not find gid for group %s. Error: %s", socketOwner, err) + } + + gid, err := strconv.ParseInt(g.Gid, 10, 32) + if err != nil { + return nil, fmt.Errorf("Found gid could not be parsed. Error: %s", err) + } + + if err = os.Chown(socket, int(uid), int(gid)); err != nil { + return nil, fmt.Errorf("Could not chown output file. Error: %s", err) + } + d := &DnsTapClient{ Listener: listener, DnsAuditMarshaller: am, } - l.Printf("Started dnstap listener, opened input socket: %s", socket) + el.Printf("Started dnstap listener, opened input socket: %s", socket) return d, nil } From 6e606390796b2f2154b6a1d27bbb3a90ccd53430 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 26 Nov 2018 13:35:30 -0800 Subject: [PATCH 43/45] minor refactoring --- ext_dnstap.go | 61 +++++++++++++++++++++++-------------------- go-audit.yaml.example | 1 + 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/ext_dnstap.go b/ext_dnstap.go index f354d46..443b4b4 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -31,36 +31,41 @@ func NewDnsTapClient(config *viper.Viper, am *DnsAuditMarshaller) (*DnsTapClient socketOwner := config.GetString("dnstap.socket_owner") + chown(socketOwner, socket) + + d := &DnsTapClient{ + Listener: listener, + DnsAuditMarshaller: am, + } + el.Printf("Started dnstap listener, opened input socket: %s", socket) + return d, nil +} + +func chown(socketOwner string, socket string) error { u, err := user.Lookup(socketOwner) if err != nil { - return nil, fmt.Errorf("Could not find uid for user %s. Error: %s", socketOwner, err) + return fmt.Errorf("Could not find uid for user %s. Error: %s", socketOwner, err) } uid, err := strconv.ParseInt(u.Uid, 10, 32) if err != nil { - return nil, fmt.Errorf("Found uid could not be parsed. Error: %s", err) + return fmt.Errorf("Found uid could not be parsed. Error: %s", err) } g, err := user.LookupGroup(socketOwner) if err != nil { - return nil, fmt.Errorf("Could not find gid for group %s. Error: %s", socketOwner, err) + return fmt.Errorf("Could not find gid for group %s. Error: %s", socketOwner, err) } gid, err := strconv.ParseInt(g.Gid, 10, 32) if err != nil { - return nil, fmt.Errorf("Found gid could not be parsed. Error: %s", err) + return fmt.Errorf("Found gid could not be parsed. Error: %s", err) } if err = os.Chown(socket, int(uid), int(gid)); err != nil { - return nil, fmt.Errorf("Could not chown output file. Error: %s", err) + return fmt.Errorf("Could not chown output file. Error: %s", err) } - - d := &DnsTapClient{ - Listener: listener, - DnsAuditMarshaller: am, - } - el.Printf("Started dnstap listener, opened input socket: %s", socket) - return d, nil + return nil } func (d *DnsTapClient) Receive() { @@ -109,26 +114,26 @@ func (d *DnsTapClient) cache(dt *dnstap.Dnstap) { } else { for i, r := range m.Answer { host := strings.TrimRight(r.Header().Name, ".") + var record string switch m.Answer[i].Header().Rrtype { case dns.TypeA: - ipv4 := m.Answer[i].(*dns.A).A.String() - d.DnsAuditMarshaller.cache.Set(ipv4, []byte(host)) - if seq, ok := d.DnsAuditMarshaller.waitingForDNS[ipv4]; ok { - if msg, ok := d.DnsAuditMarshaller.msgs[seq]; ok { - if !d.DnsAuditMarshaller.GotDNS[seq] && d.DnsAuditMarshaller.GotSaddr[seq] { - d.DnsAuditMarshaller.getDNS(msg) - } - d.DnsAuditMarshaller.completeMessage(seq) - } - delete(d.DnsAuditMarshaller.waitingForDNS, ipv4) - } + record = m.Answer[i].(*dns.A).A.String() + d.DnsAuditMarshaller.cache.Set(record, []byte(host)) case dns.TypeAAAA: - ipv6 := m.Answer[i].(*dns.AAAA).AAAA.String() - d.DnsAuditMarshaller.cache.Set(ipv6, []byte(host)) + record = m.Answer[i].(*dns.AAAA).AAAA.String() + d.DnsAuditMarshaller.cache.Set(record, []byte(host)) case dns.TypeCNAME: - cname := m.Answer[i].(*dns.CNAME).Target - d.DnsAuditMarshaller.cache.Set(cname, []byte(host)) - //el.Printf("Setting cname for %s -> %s @ %v", host, cname, time.Now().Unix()) + record := m.Answer[i].(*dns.CNAME).Target + d.DnsAuditMarshaller.cache.Set(record, []byte(host)) + } + if seq, ok := d.DnsAuditMarshaller.waitingForDNS[record]; ok { + if msg, ok := d.DnsAuditMarshaller.msgs[seq]; ok { + if !d.DnsAuditMarshaller.GotDNS[seq] && d.DnsAuditMarshaller.GotSaddr[seq] { + d.DnsAuditMarshaller.getDNS(msg) + } + d.DnsAuditMarshaller.completeMessage(seq) + } + delete(d.DnsAuditMarshaller.waitingForDNS, record) } } diff --git a/go-audit.yaml.example b/go-audit.yaml.example index 4d02e6f..450c305 100644 --- a/go-audit.yaml.example +++ b/go-audit.yaml.example @@ -9,6 +9,7 @@ socket_buffer: # Configure dnstap socket path if available dnstap: enabled: true + socket_owner: coredns socket: /var/run/dnstap.sock record_ttl: 300s max_cache_size: 10 # in mb From a81587f0a5f7dbf9ebe2c1e5c16114fbc63e5095 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 26 Nov 2018 13:42:18 -0800 Subject: [PATCH 44/45] ugh, return err --- ext_dnstap.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext_dnstap.go b/ext_dnstap.go index 443b4b4..7a78caa 100644 --- a/ext_dnstap.go +++ b/ext_dnstap.go @@ -31,7 +31,11 @@ func NewDnsTapClient(config *viper.Viper, am *DnsAuditMarshaller) (*DnsTapClient socketOwner := config.GetString("dnstap.socket_owner") - chown(socketOwner, socket) + err = chown(socketOwner, socket) + + if err != nil { + el.Fatal(err) + } d := &DnsTapClient{ Listener: listener, From 0c8907aaa3578099b5a47d2742ae8700a79dc2e4 Mon Sep 17 00:00:00 2001 From: Alan Lam Date: Mon, 26 Nov 2018 13:56:10 -0800 Subject: [PATCH 45/45] minor changes --- audit.go | 6 ++---- ext_marshaller_dnstap.go | 16 +--------------- marshaller.go | 1 - parser.go | 2 +- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/audit.go b/audit.go index 9f2a383..8bc8631 100644 --- a/audit.go +++ b/audit.go @@ -4,6 +4,8 @@ import ( "errors" "flag" "fmt" + "github.com/allegro/bigcache" + "github.com/spf13/viper" "log" "log/syslog" "os" @@ -14,10 +16,6 @@ import ( "strconv" "strings" "syscall" - - "github.com/allegro/bigcache" - - "github.com/spf13/viper" ) var l = log.New(os.Stdout, "", 0) diff --git a/ext_marshaller_dnstap.go b/ext_marshaller_dnstap.go index a39b2df..49d5477 100644 --- a/ext_marshaller_dnstap.go +++ b/ext_marshaller_dnstap.go @@ -139,25 +139,11 @@ func parseFamily(saddr string) int64 { } -func parsePortIpv4(saddr string) int64 { - a, err := strconv.ParseInt(saddr[4:6], 16, 32) - if err != nil { - el.Println(err) - } - - b, err := strconv.ParseInt(saddr[6:8], 16, 32) - if err != nil { - el.Println(err) - } - - return a*256 + b -} - func parseAddr(saddr string) (addr string) { family := parseFamily(saddr) switch family { - case 2: + case AF_INET: b, err := hex.DecodeString(saddr[8:16]) if err != nil { el.Printf("unable to decode hex to bytes: %s", err) diff --git a/marshaller.go b/marshaller.go index 9047a64..cf30d1f 100644 --- a/marshaller.go +++ b/marshaller.go @@ -102,7 +102,6 @@ func (a *AuditMarshaller) flushOld() { now := time.Now() for seq, msg := range a.msgs { if msg.CompleteAfter.Before(now) || now.Equal(msg.CompleteAfter) { - // a.waitingForDNS = make(map[string]int) a.completeMessage(seq) } } diff --git a/parser.go b/parser.go index c12da7f..82fe1db 100644 --- a/parser.go +++ b/parser.go @@ -2,7 +2,6 @@ package main import ( "bytes" - "os/user" "strconv" "strings" @@ -20,6 +19,7 @@ const ( HEADER_START_POS = 6 // Position in the audit header that the data starts COMPLETE_AFTER = time.Second * 2 // Log a message after this time or EOE SOCKADDR_LENGTH = 34 // Length of saddr event + AF_INET = 2 // Address family for ipv4 ) var uidMap = map[string]string{}