package sqlserver import ( "bytes" "encoding/binary" csm "git.loafle.net/commons/service_matcher-go" ) const ( HEADER_TYPE_PRELOGIN uint8 = 0x12 HEADER_TYPE_RESPONSE uint8 = 0x4 PL_OPTION_TOKEN_VERSION uint8 = 0x00 PL_OPTION_TOKEN_ENCRYPTION uint8 = 0x01 PL_OPTION_TOKEN_TRACEID uint8 = 0x05 PL_OPTION_TOKEN_TERMINATOR uint8 = 0xff ENCRYPT_OFF string = "Encryption is available but off." ENCRYPT_ON string = "Encryption is available and on." ENCRYPT_NOT_SUP string = "Encryption is not available." ENCRYPT_REQ string = "Encryption is required." ) type PreloginMsg struct { VersionToken uint8 VersionOffset uint16 VersionLength uint16 EncryptionToken uint8 EncryptionOffset uint16 EncryptionLength uint16 TraceIdToken uint8 TraceIdOffset uint16 TraceIdLength uint16 Terminator uint8 Options [7]uint8 TraceId [36]uint8 } type mssql struct { Type_ uint8 Status uint8 Length uint16 Channel uint16 PacketNum uint8 Window uint8 Prelogin PreloginMsg } type PreloginResponse struct { Msg [256]uint8 } type mssqlResponse struct { Type_ uint8 Status uint8 Length uint16 Channel uint16 PacketNum uint8 Window uint8 PreLoginResp PreloginResponse } type SQLServerMatcher struct { csm.Matchers isSSL bool } func (t *SQLServerMatcher) Key() string { return "SQLSERVER" } func (t *SQLServerMatcher) String() string { if t.isSSL { return "SQL Server (SSL)" } return "SQL Server" } func (t *SQLServerMatcher) IsPrePacket() bool { return false } func (t *SQLServerMatcher) HasResponse(index int) bool { return true } func (t *SQLServerMatcher) IsError(info csm.MatchInfo, index int, packet *csm.Packet) bool { return false } func (t *SQLServerMatcher) Match(info csm.MatchInfo, index int, packet *csm.Packet) bool { if packet == nil { return false } reader := new(bytes.Buffer) reader.Write(packet.Buffer) m := mssqlResponse{} if err := binary.Read(reader, binary.BigEndian, &m); err != nil { return false } if m.Type_ != HEADER_TYPE_RESPONSE { return false } if m.Length != uint16(packet.Len) { return false } switch m.PreLoginResp.Msg[m.Length-9 : m.Length-8][0] { case 0: return true case 1: t.isSSL = true return true case 2: return true case 3: t.isSSL = true return true default: return false } return false } func NewMatcher() csm.Matcher { mm := &SQLServerMatcher{} tempBuf := new(bytes.Buffer) binary.Write(tempBuf, binary.BigEndian, mssql{}) m := mssql{ Type_: HEADER_TYPE_PRELOGIN, Status: 0x01, Length: uint16(len(tempBuf.Bytes())), Channel: 0, PacketNum: 0, Window: 0, Prelogin: PreloginMsg{ VersionToken: PL_OPTION_TOKEN_VERSION, VersionOffset: 0x0010, VersionLength: 0x0006, EncryptionToken: PL_OPTION_TOKEN_ENCRYPTION, EncryptionOffset: 0x0016, EncryptionLength: 0x0001, TraceIdToken: PL_OPTION_TOKEN_TRACEID, TraceIdOffset: 0x0017, TraceIdLength: 0x0024, Terminator: PL_OPTION_TOKEN_TERMINATOR, }, } writer := new(bytes.Buffer) binary.Write(writer, binary.BigEndian, m) mm.AddPacket(csm.NewPacket(writer.Bytes(), writer.Len())) return mm }