243 lines
6.6 KiB
Go
243 lines
6.6 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
|
// the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
// Package applayer provides common definitions with common fields
|
|
// for use with application layer protocols among beats.
|
|
package applayer
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/elastic/beats/libbeat/beat"
|
|
"github.com/elastic/beats/libbeat/common"
|
|
"github.com/elastic/beats/libbeat/common/streambuf"
|
|
)
|
|
|
|
// A Message its direction indicator
|
|
type NetDirection uint8
|
|
|
|
const (
|
|
// Message due to a response by server
|
|
NetReverseDirection NetDirection = 0
|
|
|
|
// Message was send by client
|
|
NetOriginalDirection NetDirection = 1
|
|
)
|
|
|
|
// Transport type indicator. One of TransportUdp or TransportTcp
|
|
type Transport uint8
|
|
|
|
const (
|
|
TransportUDP Transport = iota
|
|
TransportTCP
|
|
)
|
|
|
|
// String returns the transport type its textual representation.
|
|
func (t Transport) String() string {
|
|
switch t {
|
|
case TransportUDP:
|
|
return "udp"
|
|
case TransportTCP:
|
|
return "tcp"
|
|
default:
|
|
return "invalid"
|
|
}
|
|
}
|
|
|
|
// A Stream provides buffering data if stream based protocol is used.
|
|
// Use Init to initialize a stream with en empty buffer and buffering limit.
|
|
// A Stream its zero value is a valid unlimited stream buffer.
|
|
type Stream struct {
|
|
// Buf provides the buffering with parsing support
|
|
Buf streambuf.Buffer
|
|
|
|
// MaxDataInStream sets the maximum number of bytes held in buffer.
|
|
// If limit is reached append function will return an error.
|
|
MaxDataInStream int
|
|
}
|
|
|
|
// A Transaction defines common fields for all application layer protocols.
|
|
type Transaction struct {
|
|
// Type is the name of the application layer protocol transaction be represented.
|
|
Type string
|
|
|
|
// Transaction source and destination IPs and Ports.
|
|
Tuple common.IPPortTuple
|
|
|
|
// Transport layer type
|
|
Transport Transport
|
|
|
|
// Src describes the transaction source/initiator endpoint
|
|
Src common.Endpoint
|
|
|
|
// Dst describes the transaction destination endpoint
|
|
Dst common.Endpoint
|
|
|
|
// Ts sets the transaction its initial timestamp
|
|
Ts TransactionTimestamp
|
|
|
|
// ResponseTime is the transaction duration in milliseconds. Should be set
|
|
// to -1 if duration is unknown
|
|
ResponseTime int32
|
|
|
|
// Status of final transaction
|
|
Status string // see libbeat/common/statuses.go
|
|
|
|
// Notes holds a list of interesting events and errors encountered when
|
|
// processing the transaction
|
|
Notes []string
|
|
|
|
// BytesIn is the number of bytes returned by destination endpoint
|
|
BytesIn uint64
|
|
|
|
// BytesOut is the number of bytes send by source endpoint to destination endpoint
|
|
BytesOut uint64
|
|
}
|
|
|
|
// TransactionTimestamp defines a transaction its initial timestamps as unix
|
|
// timestamp in milliseconds and time.Time struct.
|
|
type TransactionTimestamp struct {
|
|
Millis int64
|
|
Ts time.Time
|
|
}
|
|
|
|
// Message defines common application layer message fields. Some of these fields
|
|
// are required to initialize a Transaction (see (*Transaction).InitWithMsg).
|
|
type Message struct {
|
|
Ts time.Time
|
|
Tuple common.IPPortTuple
|
|
Transport Transport
|
|
CmdlineTuple *common.CmdlineTuple
|
|
Direction NetDirection
|
|
IsRequest bool
|
|
Size uint64
|
|
Notes []string
|
|
}
|
|
|
|
// Error code if stream exceeds max allowed size on Append.
|
|
var ErrStreamTooLarge = errors.New("Stream data too large")
|
|
|
|
// Init initializes a stream with an empty buffer and max size. Calling Init
|
|
// twice will fully re-initialize the buffer, such that calling Init before putting
|
|
// the stream in some object pool, no memory will be leaked.
|
|
func (stream *Stream) Init(maxDataInStream int) {
|
|
stream.MaxDataInStream = maxDataInStream
|
|
stream.Buf = streambuf.Buffer{}
|
|
}
|
|
|
|
// Reset will remove all bytes already read from the buffer.
|
|
func (stream *Stream) Reset() {
|
|
stream.Buf.Reset()
|
|
}
|
|
|
|
// Append adds data to the Stream its buffer. If internal buffer is nil, data
|
|
// will be retained as is. Use Write if you don't intend to retain the buffer in
|
|
// the stream.
|
|
func (stream *Stream) Append(data []byte) error {
|
|
err := stream.Buf.Append(data)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if stream.MaxDataInStream > 0 && stream.Buf.Total() > stream.MaxDataInStream {
|
|
return ErrStreamTooLarge
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Write copies data to the Stream its buffer. The data slice will not be
|
|
// retained by the buffer.
|
|
func (stream *Stream) Write(data []byte) (int, error) {
|
|
n, err := stream.Buf.Write(data)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
if stream.MaxDataInStream > 0 && stream.Buf.Total() > stream.MaxDataInStream {
|
|
return n, ErrStreamTooLarge
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
// Init initializes some common fields. ResponseTime, Status, BytesIn and
|
|
// BytesOut are initialized to zero and must be filled by application code.
|
|
func (t *Transaction) Init(
|
|
typ string,
|
|
tuple common.IPPortTuple,
|
|
transport Transport,
|
|
direction NetDirection,
|
|
time time.Time,
|
|
cmdline *common.CmdlineTuple,
|
|
notes []string,
|
|
) {
|
|
t.Type = typ
|
|
t.Transport = transport
|
|
t.Tuple = tuple
|
|
|
|
// transactions have microseconds resolution
|
|
t.Ts.Ts = time
|
|
t.Ts.Millis = int64(time.UnixNano() / 1000)
|
|
t.Src, t.Dst = common.MakeEndpointPair(tuple.BaseTuple, cmdline)
|
|
t.Notes = notes
|
|
|
|
if direction == NetReverseDirection {
|
|
t.Src, t.Dst = t.Dst, t.Src
|
|
}
|
|
}
|
|
|
|
// InitWithMsg initializes some common fields from a Message. ResponseTime,
|
|
// Status, BytesIn and BytesOut are initialized to zero and must be filled by
|
|
// application code.
|
|
func (t *Transaction) InitWithMsg(
|
|
typ string,
|
|
msg *Message,
|
|
) {
|
|
t.Init(
|
|
typ,
|
|
msg.Tuple,
|
|
msg.Transport,
|
|
msg.Direction,
|
|
msg.Ts,
|
|
msg.CmdlineTuple,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
// Event fills common event fields.
|
|
func (t *Transaction) Event(event *beat.Event) error {
|
|
event.Timestamp = t.Ts.Ts
|
|
|
|
fields := event.Fields
|
|
fields["type"] = t.Type
|
|
fields["responsetime"] = t.ResponseTime
|
|
fields["src"] = &t.Src
|
|
fields["dst"] = &t.Dst
|
|
fields["transport"] = t.Transport.String()
|
|
fields["bytes_out"] = t.BytesOut
|
|
fields["bytes_in"] = t.BytesIn
|
|
fields["status"] = t.Status
|
|
if len(t.Notes) > 0 {
|
|
fields["notes"] = t.Notes
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddNotes appends some notes to a message.
|
|
func (m *Message) AddNotes(n ...string) {
|
|
m.Notes = append(m.Notes, n...)
|
|
}
|