package ldap

import (
	"bytes"
	"encoding/binary"
	"git.loafle.net/overflow/overflow_probe/matcher/packet"
	"git.loafle.net/overflow/overflow_probe/model/scaninfo"
)

type LDAPMatcher struct {
	sendPackets []*packet.Packet
}

func (l *LDAPMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {

	if packet == nil {
		return false
	}

	buf := new(bytes.Buffer)
	buf.Write(packet.Buffer)

	ldapRecv := LDAP_RECV{}

	binary.Read(buf, binary.LittleEndian, &ldapRecv)

	if ldapRecv.MessageId != LDAP_MESSAGE_ID {
		return false
	}

	if ldapRecv.ProtocolOp != LDAP_RES_BIND {
		return false
	}

	if ldapRecv.ResultCode != LDAP_SUCCESS {
		return false
	}

	return true
}

func (l *LDAPMatcher) PacketCount() int {
	return len(l.sendPackets)
}
func (l *LDAPMatcher) Packet(index int) *packet.Packet {
	return l.sendPackets[index]
}
func (l *LDAPMatcher) ServiceName() string {
	return "LDAP"
}

func (l *LDAPMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	return false
}
func (l *LDAPMatcher) IsNoResponse(index int) bool {

	if index == 1 {
		return true
	}

	return false
}

func (l *LDAPMatcher) IsPrePacket() bool {
	return false
}

func NewLDAPMatcher() *LDAPMatcher {

	ls := LDAP_SEND{
		DefaultCode:      0x30,
		PacketLength:     0x0c, // size -2
		NextType1:        0x02,
		NextTypeLength1:  0x01,
		MessageId:        LDAP_MESSAGE_ID,
		ProtocolOp:       LDAP_REQ_BIND,
		ProtocolOpLength: 0x07,
		NextType2:        0x02,
		NextTypeLength2:  0x01,
		Version:          LDAP_VERSION3,
		NextType3:        0x04,
		NextTypeLength3:  0x00,
		Auth:             LDAP_AUTH_SIMPLE,
		AuthLength:       0x00,
	}

	mCache := new(bytes.Buffer)
	binary.Write(mCache, binary.LittleEndian, ls)

	sendByte1 := mCache.Bytes()

	lm := LDAPMatcher{
	//sendPackets: make([][]byte, 2),
	}

	pp := packet.NewPacket(sendByte1, len(sendByte1))

	lm.sendPackets = append(lm.sendPackets, pp)

	lq := LDAP_QUIT{
		DefaultCode:      0x30,
		UnknwonCode1:     0x84,
		PacketLength:     0x05,
		NextType1:        0x02,
		NextTypeLength1:  0x01,
		MessageId:        LDAP_MESSAGE_ID_QUIT,
		ProtocolOp:       LDAP_REQ_UNBIND,
		protocolOpLength: 0x00,
	}

	lqBuffer := new(bytes.Buffer)
	binary.Write(lqBuffer, binary.BigEndian, lq)

	sendByte2 := lqBuffer.Bytes()

	pp2 := packet.NewPacket(sendByte2, len(sendByte2))

	lm.sendPackets = append(lm.sendPackets, pp2)

	return &lm

}

type LDAP_SEND struct {
	DefaultCode  uint8
	PacketLength uint8

	NextType1       uint8
	NextTypeLength1 uint8

	MessageId uint8

	ProtocolOp       uint8
	ProtocolOpLength uint8
	NextType2        uint8
	NextTypeLength2  uint8

	Version uint8

	NextType3       uint8
	NextTypeLength3 uint8
	Auth            uint8
	AuthLength      uint8
}

type LDAP_RECV struct {
	DefaultCode  uint8
	UnknwonCode1 uint8
	EndCode11    uint8
	EndCode12    uint8

	MessageId uint8

	ProtocolOp   uint8
	UnknwonCode2 uint8
	EndCode21    uint8
	EndCode22    uint8

	ResultCode uint8

	UnknwonCode3 uint8
	UnknwonCode4 uint8
	Auth         uint8
	UnknwonCode5 uint8
}

type LDAP_QUIT struct {
	DefaultCode  uint8
	UnknwonCode1 uint8

	PacketLength uint32

	NextType1       uint8
	NextTypeLength1 uint8

	MessageId uint8

	ProtocolOp uint8

	protocolOpLength uint8
}

const (
	LDAP_MESSAGE_ID      = 0x99
	LDAP_MESSAGE_ID_QUIT = 0x89

	LDAP_VERSION3 = 3

	LDAP_SUCCESS = 0x00

	LDAP_REQ_BIND = 0x60

	LDAP_REQ_UNBIND = 0x42

	LDAP_RES_BIND = 0x61

	LDAP_AUTH_SIMPLE = 0x80
)
