in packetbeat/protos/mysql/mysql.go [805:999]
func (mysql *mysqlPlugin) parseMysqlExecuteStatement(data []byte, stmtdata *mysqlStmtData) []string {
dataLen := len(data)
if dataLen < 14 {
logp.Debug("mysql", "Data too small")
return nil
}
var paramType, paramUnsigned uint8
nparamType := []uint8{}
paramString := []string{}
nparam := stmtdata.numOfParameters
offset := 0
// mysql hdr
offset += 4
// cmd type
offset++
// stmt id
offset += 4
// flags
offset++
// iterations
offset += 4
// null-bitmap
if nparam > 0 {
offset += (nparam + 7) / 8
} else {
return nil
}
// stmt bound
if dataLen <= offset {
logp.Debug("mysql", "Data too small")
return nil
}
stmtBound := data[offset]
offset++
paramOffset := offset
if stmtBound == 1 {
paramOffset += nparam * 2
if dataLen <= paramOffset {
logp.Debug("mysql", "Data too small to contain parameters")
return nil
}
// First call or rebound (1)
for stmtPos := 0; stmtPos < nparam; stmtPos++ {
paramType = uint8(data[offset])
offset++
nparamType = append(nparamType, paramType)
logp.Debug("mysqldetailed", "type = %d", paramType)
paramUnsigned = uint8(data[offset])
offset++
if paramUnsigned != 0 {
logp.Debug("mysql", "Illegal param unsigned")
return nil
}
}
// Save param type info
stmtdata.nparamType = nparamType
} else {
// Subsequent call (0)
if len(stmtdata.nparamType) > 0 {
// get saved param type info
nparamType = stmtdata.nparamType
} else {
return nil
}
}
for stmtPos := 0; stmtPos < nparam; stmtPos++ {
paramType = nparamType[stmtPos]
// dissect parameter on paramType
switch paramType {
// FIELD_TYPE_TINY
case 0x01:
valueString := strconv.Itoa(int(data[paramOffset]))
paramString = append(paramString, valueString)
paramOffset++
// FIELD_TYPE_SHORT
case 0x02:
if dataLen < paramOffset+2 {
logp.Debug("mysql", "Data too small")
return nil
}
valueString := strconv.Itoa(int(binary.LittleEndian.Uint16(data[paramOffset:])))
paramString = append(paramString, valueString)
paramOffset += 2
// FIELD_TYPE_LONG
case 0x03:
if dataLen < paramOffset+4 {
logp.Debug("mysql", "Data too small")
return nil
}
valueString := strconv.Itoa(int(binary.LittleEndian.Uint32(data[paramOffset:])))
paramString = append(paramString, valueString)
paramOffset += 4
// FIELD_TYPE_FLOAT
case 0x04:
paramString = append(paramString, "TYPE_FLOAT")
paramOffset += 4
// FIELD_TYPE_DOUBLE
case 0x05:
paramString = append(paramString, "TYPE_DOUBLE")
paramOffset += 4
// FIELD_TYPE_NULL
case 0x06:
paramString = append(paramString, "TYPE_NULL")
// FIELD_TYPE_LONGLONG
case 0x08:
if dataLen < paramOffset+8 {
logp.Debug("mysql", "Data too small")
return nil
}
valueString := strconv.FormatInt(int64(binary.LittleEndian.Uint64(data[paramOffset:paramOffset+8])), 10)
paramString = append(paramString, valueString)
paramOffset += 8
// FIELD_TYPE_TIMESTAMP
// FIELD_TYPE_DATETIME
// FIELD_TYPE_DATE
case 0x07, 0x0c, 0x0a:
var year, month, day, hour, minute, second string
paramLen := int(data[paramOffset])
if dataLen < paramOffset+paramLen+1 {
logp.Debug("mysql", "Data too small")
return nil
}
paramOffset++
if paramLen >= 2 {
year = strconv.Itoa(int(binary.LittleEndian.Uint16(data[paramOffset:])))
}
if paramLen >= 4 {
month = strconv.Itoa(int(data[paramOffset+2]))
day = strconv.Itoa(int(data[paramOffset+3]))
}
if paramLen >= 7 {
hour = strconv.Itoa(int(data[paramOffset+4]))
minute = strconv.Itoa(int(data[paramOffset+5]))
second = strconv.Itoa(int(data[paramOffset+6]))
}
// If paramLen is greater or equal to 11
// then nanoseconds are also available.
// We do not handle them.
datetime := year + "/" + month + "/" + day + " " + hour + ":" + minute + ":" + second
paramString = append(paramString, datetime)
paramOffset += paramLen
// FIELD_TYPE_TIME
case 0x0b:
paramLen := int(data[paramOffset])
if dataLen < paramOffset+paramLen+1 {
logp.Debug("mysql", "Data too small")
return nil
}
paramOffset++
paramString = append(paramString, "TYPE_TIME")
paramOffset += paramLen
// FIELD_TYPE_VAR_STRING
// FIELD_TYPE_BLOB
// FIELD_TYPE_STRING
case 0xf6, 0xfc, 0xfd, 0xfe:
paramLen := int(data[paramOffset])
paramOffset++
switch paramLen {
case 0xfc: /* 252 - 64k chars */
paramLen16 := int(binary.LittleEndian.Uint16(data[paramOffset : paramOffset+2]))
if dataLen < paramOffset+paramLen16+2 {
logp.Debug("mysql", "Data too small")
return nil
}
paramOffset += 2
paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen16]))
paramOffset += paramLen16
case 0xfd: /* 64k - 16M chars */
paramLen24 := int(leUint24(data[paramOffset : paramOffset+3]))
if dataLen < paramOffset+paramLen24+3 {
logp.Debug("mysql", "Data too small")
return nil
}
paramOffset += 3
paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen24]))
paramOffset += paramLen24
default: /* < 252 chars */
if dataLen < paramOffset+paramLen {
logp.Debug("mysql", "Data too small")
return nil
}
paramString = append(paramString, string(data[paramOffset:paramOffset+paramLen]))
paramOffset += paramLen
}
default:
logp.Debug("mysql", "Unknown param type")
return nil
}
}
return paramString
}