156 lines
3.0 KiB
Go
156 lines
3.0 KiB
Go
|
package pgsql
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"loafle.com/overflow/collector/core/scan/service/matcher/packet"
|
||
|
"loafle.com/overflow/collector/discovery/types"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
RESPONSE_TYPE_ERR uint8 = 0x45
|
||
|
)
|
||
|
|
||
|
type pgsql struct {
|
||
|
Len uint32
|
||
|
MessageType uint16
|
||
|
_ uint16
|
||
|
Name [5]byte
|
||
|
NameValue byte
|
||
|
Db [9]byte
|
||
|
DBValue byte
|
||
|
Encoding [16]byte
|
||
|
EncodingValue [5]byte
|
||
|
DateStyle [10]byte
|
||
|
DateStyleValue [4]byte
|
||
|
TimeZone [9]byte
|
||
|
TimeZoneValue [11]byte
|
||
|
ExtraDigits [19]byte
|
||
|
ExtraDigitsValue uint16
|
||
|
End byte
|
||
|
}
|
||
|
|
||
|
type pgsqlErrResponse struct {
|
||
|
ResponseType uint8
|
||
|
Len [4]byte
|
||
|
Severity [6]byte
|
||
|
_ byte
|
||
|
Code [6]byte
|
||
|
_ byte
|
||
|
Message [53]byte
|
||
|
}
|
||
|
|
||
|
type PostgreSQLMatcher struct {
|
||
|
packets []*packet.Packet
|
||
|
}
|
||
|
|
||
|
func NewPostgreSQLMatcher() *PostgreSQLMatcher {
|
||
|
|
||
|
pgSqlMatcher := &PostgreSQLMatcher{}
|
||
|
|
||
|
pg := pgsql{}
|
||
|
|
||
|
pg.Len = 0x00000065
|
||
|
pg.MessageType = 0x0003
|
||
|
|
||
|
var name [5]byte
|
||
|
copy(name[:], "user")
|
||
|
pg.Name = name
|
||
|
pg.NameValue = 0x00
|
||
|
|
||
|
var db [9]byte
|
||
|
copy(db[:], "database")
|
||
|
pg.Db = db
|
||
|
pg.DBValue = 0x00
|
||
|
|
||
|
var encoding [16]byte
|
||
|
copy(encoding[:], "client_encoding")
|
||
|
pg.Encoding = encoding
|
||
|
|
||
|
var encodingValue [5]byte
|
||
|
copy(encodingValue[:], "UTF8")
|
||
|
pg.EncodingValue = encodingValue
|
||
|
|
||
|
var dateStyle [10]byte
|
||
|
copy(dateStyle[:], "DateStyle")
|
||
|
pg.DateStyle = dateStyle
|
||
|
|
||
|
var dateStyleValue [4]byte
|
||
|
copy(dateStyleValue[:], "ISO")
|
||
|
pg.DateStyleValue = dateStyleValue
|
||
|
|
||
|
var timeZone [9]byte
|
||
|
copy(timeZone[:], "TimeZone")
|
||
|
pg.TimeZone = timeZone
|
||
|
|
||
|
var timeZoneValue [11]byte
|
||
|
copy(timeZoneValue[:], "Asia/Seoul")
|
||
|
pg.TimeZoneValue = timeZoneValue
|
||
|
|
||
|
var extraDigit [19]byte
|
||
|
copy(extraDigit[:], "extra_float_digits")
|
||
|
pg.ExtraDigits = extraDigit
|
||
|
|
||
|
pg.ExtraDigitsValue = 0x3200
|
||
|
|
||
|
writer := new(bytes.Buffer)
|
||
|
binary.Write(writer, binary.BigEndian, pg)
|
||
|
|
||
|
pgSqlMatcher.packets = append(pgSqlMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len()))
|
||
|
|
||
|
return pgSqlMatcher
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) ServiceName() string {
|
||
|
return "PostgreSQL"
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) PacketCount() int {
|
||
|
return len(t.packets)
|
||
|
}
|
||
|
func (t *PostgreSQLMatcher) Packet(index int) *packet.Packet {
|
||
|
return t.packets[index]
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) IsError(index int, packet *packet.Packet, info *types.ServiceScanInfo) bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) IsNoResponse(index int) bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) IsPrePacket() bool {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (t *PostgreSQLMatcher) Match(index int, packet *packet.Packet, info *types.ServiceScanInfo) bool {
|
||
|
|
||
|
if packet == nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
reader := new(bytes.Buffer)
|
||
|
reader.Write(packet.Buffer)
|
||
|
|
||
|
pg := pgsqlErrResponse{}
|
||
|
if err := binary.Read(reader, binary.BigEndian, &pg); err != nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if pg.ResponseType != RESPONSE_TYPE_ERR {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
severity := string(pg.Severity[1:])
|
||
|
if severity != "FATAL" && severity != "ERROR" {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if string(pg.Code[1:]) != "28000" {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
|
||
|
}
|