197 lines
4.4 KiB
Go

package dnsProxy
import (
"bytes"
"encoding/binary"
"net"
"strings"
)
type ResourceRecord interface {
EncodeResource() []byte
}
type ResourceRecordHeader struct {
Name Name
Type uint16
Class uint16
TTL uint32
}
func (q ResourceRecordHeader) EncodeHeader() []byte {
buf := bytes.NewBuffer([]byte{})
buf.Write(q.Name.Encode())
buf.Write(binary.BigEndian.AppendUint16([]byte{}, q.Type))
buf.Write(binary.BigEndian.AppendUint16([]byte{}, q.Class))
buf.Write(binary.BigEndian.AppendUint32([]byte{}, q.TTL))
return buf.Bytes()
}
type Name struct {
Parts []string
}
func (n Name) String() string {
return strings.Join(n.Parts, ".")
}
func (n Name) Encode() []byte {
buf := bytes.NewBuffer([]byte{})
for _, part := range n.Parts {
partLen := byte(len(part)) & 0x3F
buf.WriteByte(partLen)
buf.Write([]byte(part)[0:partLen])
}
buf.WriteByte(0)
return buf.Bytes()
}
type Flags struct {
QR uint8
Opcode uint8
AA uint8
TC uint8
RD uint8
RA uint8
Z1 uint8
Z2 uint8
Z3 uint8
RCode uint8
}
func (f Flags) Encode() []byte {
return []byte{
f.QR&0x1<<7 + f.Opcode&0xF<<3 + f.AA&0x1<<2 + f.TC&0x1<<1 + f.RD&0x1<<0,
f.RA&0x1<<7 + f.Z1&0x1<<6 + f.Z2&0x1<<5 + f.Z3&0x1<<4 + f.RCode&0xF<<0,
}
}
type Question struct {
QName Name
QType uint16
QClass uint16
}
func (q Question) EncodeQuestion() []byte {
buf := bytes.NewBuffer([]byte{})
buf.Write(q.QName.Encode())
buf.Write(binary.BigEndian.AppendUint16([]byte{}, q.QType))
buf.Write(binary.BigEndian.AppendUint16([]byte{}, q.QClass))
return buf.Bytes()
}
type Address struct {
ResourceRecordHeader
Address net.IP
}
func (a Address) EncodeResource() []byte {
rr := bytes.NewBuffer([]byte{})
rr.Write(a.ResourceRecordHeader.EncodeHeader())
rr.Write([]byte{0x00, 0x04})
rr.Write(a.Address[:])
return rr.Bytes()
}
type NameServer struct {
ResourceRecordHeader
NSDName Name
}
func (a NameServer) EncodeResource() []byte {
rdataBytes := a.NSDName.Encode()
rr := bytes.NewBuffer([]byte{})
rr.Write(a.ResourceRecordHeader.EncodeHeader())
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(rdataBytes))))
rr.Write(rdataBytes)
return rr.Bytes()
}
type CName struct {
ResourceRecordHeader
CName Name
}
func (a CName) EncodeResource() []byte {
rdataBytes := a.CName.Encode()
rr := bytes.NewBuffer([]byte{})
rr.Write(a.ResourceRecordHeader.EncodeHeader())
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(rdataBytes))))
rr.Write(rdataBytes)
return rr.Bytes()
}
type Authority struct {
ResourceRecordHeader
MName Name
RName Name
Serial uint32
Refresh uint32
Retry uint32
Expire uint32
Minimum uint32
}
func (a Authority) EncodeResource() []byte {
rdata := bytes.NewBuffer([]byte{})
rdata.Write(a.MName.Encode())
rdata.Write(a.RName.Encode())
rdata.Write(binary.BigEndian.AppendUint32([]byte{}, a.Serial))
rdata.Write(binary.BigEndian.AppendUint32([]byte{}, a.Refresh))
rdata.Write(binary.BigEndian.AppendUint32([]byte{}, a.Retry))
rdata.Write(binary.BigEndian.AppendUint32([]byte{}, a.Expire))
rdata.Write(binary.BigEndian.AppendUint32([]byte{}, a.Minimum))
rdataBytes := rdata.Bytes()
rr := bytes.NewBuffer([]byte{})
rr.Write(a.ResourceRecordHeader.EncodeHeader())
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(rdataBytes))))
rr.Write(rdataBytes)
return rr.Bytes()
}
type Unknown struct {
ResourceRecordHeader
Data []byte
}
func (u Unknown) EncodeResource() []byte {
rr := bytes.NewBuffer([]byte{})
rr.Write(u.ResourceRecordHeader.EncodeHeader())
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(u.Data))))
rr.Write(u.Data)
return rr.Bytes()
}
type Message struct {
ID uint16
Flags Flags
QD []Question
AN []ResourceRecord
NS []ResourceRecord
AR []ResourceRecord
}
func (m Message) Encode() []byte {
rr := bytes.NewBuffer([]byte{})
rr.Write(binary.BigEndian.AppendUint16([]byte{}, m.ID))
rr.Write(m.Flags.Encode())
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(m.QD))))
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(m.AN))))
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(m.NS))))
rr.Write(binary.BigEndian.AppendUint16([]byte{}, uint16(len(m.AR))))
for _, q := range m.QD {
rr.Write(q.EncodeQuestion())
}
for _, a := range m.AN {
rr.Write(a.EncodeResource())
}
for _, ns := range m.NS {
rr.Write(ns.EncodeResource())
}
for _, a := range m.AR {
rr.Write(a.EncodeResource())
}
return rr.Bytes()
}