package dns

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

type Dns_frame_header struct {
	Transaction_id uint16
	Flags          uint16
	Questions      uint16
	Answer_rrs     uint16
	Authority_rrs  uint16
	Additional_rrs uint16
}

type Dns_query_section struct {
	Name       uint8
	Query_type uint16
	Class_type uint16
}

type Dns_authority_section struct {
	Name                          uint8
	Auth_type                     uint16
	Class_type                    uint16
	Time_to_live                  uint32
	Data_length                   uint16
	Primary_name_server           [20]uint8
	Responsible_authority_mailbox [24]uint8
	Serial_number                 uint32
	Refresh_interval              uint32
	Retry_interval                uint32
	Expire_limit                  uint32
	Minium_ttl                    uint32
}

type DNSMatcher struct {
	packets []*packet.Packet
}

func NewDnsMatcher() *DNSMatcher {

	m := &DNSMatcher{}

	header := Dns_frame_header{
		Transaction_id: 0x2a88,
		Flags:          0x0100,
		Questions:      1,
		Answer_rrs:     0,
		Authority_rrs:  0,
		Additional_rrs: 0,
	}

	query := Dns_query_section{
		Name:       0,
		Query_type: 1,
		Class_type: 1,
	}

	buf := new(bytes.Buffer)
	binary.Write(buf, binary.BigEndian, header)
	binary.Write(buf, binary.BigEndian, query)

	m.packets = append(m.packets, packet.NewPacket(buf.Bytes(), buf.Len()))

	return m
}

func (t *DNSMatcher) ServiceName() string {
	return "DNS"
}

func (t *DNSMatcher) PacketCount() int {
	return len(t.packets)
}
func (t *DNSMatcher) Packet(index int) *packet.Packet {
	return t.packets[index]
}

func (t *DNSMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	return false
}

func (t *DNSMatcher) IsNoResponse(index int) bool {
	return false
}

func (t *DNSMatcher) IsPrePacket() bool {
	return false
}

func (t *DNSMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	if packet == nil {
		return false
	}
	if packet.Len <= 0 {
		return false
	}

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

	h := Dns_frame_header{}
	if err := binary.Read(reader, binary.BigEndian, &h); err != nil {
		return false
	}

	if h.Transaction_id != 0x2a88 {
		return false
	}
	if h.Flags != 0x8180 && h.Flags != 0x8182 {
		return false
	}
	if h.Questions != 1 {
		return false
	}
	if h.Answer_rrs != 0 {
		return false
	}
	if h.Authority_rrs != 0 && h.Authority_rrs != 1 {
		return false
	}
	if h.Additional_rrs != 0 && h.Additional_rrs != 1 {
		return false
	}

	q := Dns_query_section{}
	if err := binary.Read(reader, binary.BigEndian, &q); err != nil {
		return false
	}
	if q.Name != 0 {
		return false
	}
	if q.Query_type != 1 {
		return false
	}
	if q.Class_type != 1 {
		return false
	}

	return true
}
func (t *DNSMatcher) IsSend(port int) bool {
	if port == 53 {
		return true
	}
	return false
}
