diff --git a/matcher/pgsql/pgsql.go b/matcher/pgsql/pgsql.go new file mode 100644 index 0000000..13bf7e1 --- /dev/null +++ b/matcher/pgsql/pgsql.go @@ -0,0 +1,156 @@ +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 + +} \ No newline at end of file diff --git a/matcher/pgsql/pgsql_test.go b/matcher/pgsql/pgsql_test.go new file mode 100644 index 0000000..8ef9047 --- /dev/null +++ b/matcher/pgsql/pgsql_test.go @@ -0,0 +1,71 @@ +package pgsql + + +import ( + "loafle.com/overflow/collector/core/scan/service/matcher/packet" + "net" + "testing" + "crypto/tls" +) + +func TestPG(t *testing.T) { + m := NewPostgreSQLMatcher() + + conn, err := net.Dial("tcp", "192.168.1.88:5432") //107 + if err != nil { + t.Error(err) + return + } + defer conn.Close() + + for i := 0; i < m.PacketCount(); i++ { + + pack := m.Packet(i) + conn.Write(pack.Buffer) + bytes := make([]byte, 1024) + n, _ := conn.Read(bytes) + p := packet.NewPacket(bytes, n) + + if m.Match(i, p, nil) { + t.Log("PostgreSQL found") + return + } + + t.Error("PostgreSQL not found") + } +} + +func TestSqlTLS(t *testing.T) { + conn, err := tls.Dial( + "tcp", + "192.168.1.107:5432", + &tls.Config{ + InsecureSkipVerify: true, + ServerName: "192.168.1.107", + }, + ) + + if err != nil { + t.Error(err) + return + } + + defer conn.Close() + + m := NewPostgreSQLMatcher() + for i := 0; i < m.PacketCount(); i++ { + + pack := m.Packet(i) + conn.Write(pack.Buffer) + bytes := make([]byte, 1024) + n, _ := conn.Read(bytes) + p := packet.NewPacket(bytes, n) + + if m.Match(i, p, nil) { + t.Log("PostgreSQL found") + return + } + + t.Error("PostgreSQL not found") + } +}