func (p *parser) parseString(buf *streambuf.Buffer) (common.NetString, bool, bool) { line, err := buf.UntilCRLF() if err != nil { return empty, true, false } if len(line) == 3 && line[1] == '-' && line[2] == '1' { return nilStr, true, true } length, err := parseInt(line[1:]) if err != nil { logp.Err("Failed to read bulk message: %s", err) return empty, false, false } content, err := buf.CollectWithSuffix(int(length), []byte("\r\n")) if err != nil { if err != streambuf.ErrNoMoreBytes { return common.NetString{}, false, false } return common.NetString{}, true, false } return common.NetString(content), true, true }
func (p *parser) parseSimpleString(buf *streambuf.Buffer) (common.NetString, bool, bool) { line, err := buf.UntilCRLF() if err != nil { return empty, true, false } return common.NetString(line[1:]), true, true }
func (redis *Redis) newTransaction(requ, resp *redisMessage) common.MapStr { error := common.OK_STATUS if resp.IsError { error = common.ERROR_STATUS } var returnValue map[string]common.NetString if resp.IsError { returnValue = map[string]common.NetString{ "error": resp.Message, } } else { returnValue = map[string]common.NetString{ "return_value": resp.Message, } } src := &common.Endpoint{ Ip: requ.TcpTuple.Src_ip.String(), Port: requ.TcpTuple.Src_port, Proc: string(requ.CmdlineTuple.Src), } dst := &common.Endpoint{ Ip: requ.TcpTuple.Dst_ip.String(), Port: requ.TcpTuple.Dst_port, Proc: string(requ.CmdlineTuple.Dst), } if requ.Direction == tcp.TcpDirectionReverse { src, dst = dst, src } // resp_time in milliseconds responseTime := int32(resp.Ts.Sub(requ.Ts).Nanoseconds() / 1e6) event := common.MapStr{ "@timestamp": common.Time(requ.Ts), "type": "redis", "status": error, "responsetime": responseTime, "redis": returnValue, "method": common.NetString(bytes.ToUpper(requ.Method)), "resource": requ.Path, "query": requ.Message, "bytes_in": uint64(requ.Size), "bytes_out": uint64(resp.Size), "src": src, "dst": dst, } if redis.SendRequest { event["request"] = requ.Message } if redis.SendResponse { event["response"] = resp.Message } return event }
func (p *parser) parseArray(depth int, buf *streambuf.Buffer) (common.NetString, bool, bool, bool) { line, err := buf.UntilCRLF() if err != nil { if isDebug { debugf("End of line not found, waiting for more data") } return empty, false, false, false } if isDebug { debugf("line %s: %d", line, buf.BufferConsumed()) } if len(line) == 3 && line[1] == '-' && line[2] == '1' { return nilStr, false, true, true } if len(line) == 2 && line[1] == '0' { return emptyArr, false, true, true } count, err := parseInt(line[1:]) if err != nil { logp.Err("Failed to read number of bulk messages: %s", err) return empty, false, false, false } if count < 0 { return nilStr, false, true, true } else if count == 0 { // should not happen, but handle just in case ParseInt did return 0 return emptyArr, false, true, true } // invariant: count > 0 // try to allocate content array right on stack var content [][]byte const arrayBufferSize = 32 if int(count) <= arrayBufferSize { var arrayBuffer [arrayBufferSize][]byte content = arrayBuffer[:0] } else { content = make([][]byte, 0, count) } contentLen := 0 // read sub elements iserror := false for i := 0; i < int(count); i++ { var value common.NetString var ok, complete bool value, iserror, ok, complete := p.dispatch(depth+1, buf) if !ok || !complete { if isDebug { debugf("Array incomplete") } return empty, iserror, ok, complete } content = append(content, []byte(value)) contentLen += len(value) } // handle top-level request command if depth == 0 && isRedisCommand(content[0]) { p.message.isRequest = true p.message.method = content[0] if len(content) > 1 { p.message.path = content[1] } var value common.NetString if contentLen > 1 { tmp := make([]byte, contentLen+(len(content)-1)*1) join(tmp, content, []byte(" ")) value = common.NetString(tmp) } else { value = common.NetString(content[0]) } return value, iserror, true, true } // return redis array: [a, b, c] tmp := make([]byte, 2+contentLen+(len(content)-1)*2) tmp[0] = '[' join(tmp[1:], content, []byte(", ")) tmp[len(tmp)-1] = ']' value := common.NetString(tmp) return value, iserror, true, true }
size int message common.NetString method common.NetString path common.NetString next *redisMessage } const ( start = iota bulkArray simpleMessage ) var ( empty = common.NetString("") emptyArr = common.NetString("[]") nilStr = common.NetString("nil") ) // Keep sorted for future command addition var redisCommands = map[string]struct{}{ "APPEND": {}, "AUTH": {}, "BGREWRITEAOF": {}, "BGSAVE": {}, "BITCOUNT": {}, "BITOP": {}, "BITPOS": {}, "BLPOP": {}, "BRPOP": {},
func createEvent( ts time.Time, f *biFlow, isOver bool, intNames, uintNames, floatNames []string, ) common.MapStr { event := common.MapStr{ "@timestamp": common.Time(ts), "start_time": common.Time(f.createTS), "last_time": common.Time(f.ts), "type": "flow", "flow_id": common.NetString(f.id.Serialize()), "final": isOver, } source := common.MapStr{} dest := common.MapStr{} // add ethernet layer meta data if src, dst, ok := f.id.EthAddr(); ok { source["mac"] = net.HardwareAddr(src).String() dest["mac"] = net.HardwareAddr(dst).String() } // add vlan if vlan := f.id.OutterVLan(); vlan != nil { event["outer_vlan"] = binary.LittleEndian.Uint16(vlan) } if vlan := f.id.VLan(); vlan != nil { event["vlan"] = binary.LittleEndian.Uint16(vlan) } // add icmp if icmp := f.id.ICMPv4(); icmp != nil { event["icmp_id"] = binary.LittleEndian.Uint16(icmp) } else if icmp := f.id.ICMPv6(); icmp != nil { event["icmp_id"] = binary.LittleEndian.Uint16(icmp) } // ipv4 layer meta data if src, dst, ok := f.id.OutterIPv4Addr(); ok { source["outer_ip"] = net.IP(src).String() dest["outer_ip"] = net.IP(dst).String() } if src, dst, ok := f.id.IPv4Addr(); ok { source["ip"] = net.IP(src).String() dest["ip"] = net.IP(dst).String() } // ipv6 layer meta data if src, dst, ok := f.id.OutterIPv6Addr(); ok { source["outer_ipv6"] = net.IP(src).String() dest["outer_ipv6"] = net.IP(dst).String() } if src, dst, ok := f.id.IPv6Addr(); ok { source["ipv6"] = net.IP(src).String() dest["ipv6"] = net.IP(dst).String() } // udp layer meta data if src, dst, ok := f.id.UDPAddr(); ok { source["port"] = binary.LittleEndian.Uint16(src) dest["port"] = binary.LittleEndian.Uint16(dst) event["transport"] = "udp" } // tcp layer meta data if src, dst, ok := f.id.TCPAddr(); ok { source["port"] = binary.LittleEndian.Uint16(src) dest["port"] = binary.LittleEndian.Uint16(dst) event["transport"] = "tcp" } if id := f.id.ConnectionID(); id != nil { event["connection_id"] = base64.StdEncoding.EncodeToString(id) } if f.stats[0] != nil { source["stats"] = encodeStats(f.stats[0], intNames, uintNames, floatNames) } if f.stats[1] != nil { dest["stats"] = encodeStats(f.stats[1], intNames, uintNames, floatNames) } event["source"] = source event["dest"] = dest return event }
func (parser *parser) parseHeader(m *message, data []byte) (bool, bool, int) { if m.Headers == nil { m.Headers = make(map[string]common.NetString) } i := bytes.Index(data, []byte(":")) if i == -1 { // Expected \":\" in headers. Assuming incomplete" return true, false, 0 } config := parser.config // enabled if required. Allocs for parameters slow down parser big times if isDetailed { detailedf("Data: %s", data) detailedf("Header: %s", data[:i]) } // skip folding line for p := i + 1; p < len(data); { q := bytes.Index(data[p:], constCRLF) if q == -1 { // Assuming incomplete return true, false, 0 } p += q if len(data) > p && (data[p+1] == ' ' || data[p+1] == '\t') { p = p + 2 } else { var headerNameBuf [140]byte headerName := toLower(headerNameBuf[:], data[:i]) headerVal := trim(data[i+1 : p]) if isDebug { debugf("Header: '%s' Value: '%s'\n", data[:i], headerVal) } // Headers we need for parsing. Make sure we always // capture their value if bytes.Equal(headerName, nameContentLength) { m.ContentLength, _ = parseInt(headerVal) m.hasContentLength = true } else if bytes.Equal(headerName, nameContentType) { m.ContentType = headerVal } else if bytes.Equal(headerName, nameTransferEncoding) { m.TransferEncoding = common.NetString(headerVal) } else if bytes.Equal(headerName, nameConnection) { m.connection = headerVal } if len(config.RealIPHeader) > 0 && bytes.Equal(headerName, []byte(config.RealIPHeader)) { m.RealIP = headerVal } if config.SendHeaders { if !config.SendAllHeaders { _, exists := config.HeadersWhitelist[string(headerName)] if !exists { return true, true, p + 2 } } if val, ok := m.Headers[string(headerName)]; ok { composed := make([]byte, len(val)+len(headerVal)+2) off := copy(composed, val) off = copy(composed[off:], []byte(", ")) copy(composed[off:], headerVal) m.Headers[string(headerName)] = composed } else { m.Headers[string(headerName)] = headerVal } } return true, true, p + 2 } } return true, false, len(data) }
func (*parser) parseHTTPLine(s *stream, m *message) (cont, ok, complete bool) { m.start = s.parseOffset i := bytes.Index(s.data[s.parseOffset:], []byte("\r\n")) if i == -1 { return false, true, false } // Very basic tests on the first line. Just to check that // we have what looks as an HTTP message var version []byte var err error fline := s.data[s.parseOffset:i] if len(fline) < 8 { if isDebug { debugf("First line too small") } return false, false, false } if bytes.Equal(fline[0:5], []byte("HTTP/")) { //RESPONSE m.IsRequest = false version = fline[5:8] m.StatusCode, m.StatusPhrase, err = parseResponseStatus(fline[9:]) if err != nil { logp.Warn("Failed to understand HTTP response status: %s", fline[9:]) return false, false, false } if isDebug { debugf("HTTP status_code=%d, status_phrase=%s", m.StatusCode, m.StatusPhrase) } } else { // REQUEST slices := bytes.Fields(fline) if len(slices) != 3 { if isDebug { debugf("Couldn't understand HTTP request: %s", fline) } return false, false, false } m.Method = common.NetString(slices[0]) m.RequestURI = common.NetString(slices[1]) if bytes.Equal(slices[2][:5], []byte("HTTP/")) { m.IsRequest = true version = slices[2][5:] } else { if isDebug { debugf("Couldn't understand HTTP version: %s", fline) } return false, false, false } } m.version.major, m.version.minor, err = parseVersion(version) if err != nil { if isDebug { debugf("Failed to understand HTTP version: %v", version) } m.version.major = 1 m.version.minor = 0 } if isDebug { debugf("HTTP version %d.%d", m.version.major, m.version.minor) } // ok so far s.parseOffset = i + 2 m.headerOffset = s.parseOffset s.parseState = stateHeaders return true, true, true }