all repos

scratch @ 77539dbab7c4667298a1184973b0ad6c0819c0bb

⭐ me doing recreational ~~drugs~~ programming
8 files changed, 320 insertions(+), 0 deletions(-)
dns: ch1
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-03-21 12:27:53 +0200
Change ID: lmopynqxtwnlswmsrnsxqnkmqnkomtqs
Parent: 85452e1
A dns-server/go.mod
···
                
                1
                +module dns-server

              
                
                2
                +

              
                
                3
                +go 1.26.0

              
A dns-server/header.go
···
                
                1
                +package main

              
                
                2
                +

              
                
                3
                +import (

              
                
                4
                +	"bytes"

              
                
                5
                +	"encoding/binary"

              
                
                6
                +	"fmt"

              
                
                7
                +)

              
                
                8
                +

              
                
                9
                +type ResultCode uint

              
                
                10
                +

              
                
                11
                +const (

              
                
                12
                +	NOERROR ResultCode = iota

              
                
                13
                +	FORMERR

              
                
                14
                +	SERVFAIL

              
                
                15
                +	NXDOMAIN

              
                
                16
                +	NOTIMP

              
                
                17
                +	REFUSED

              
                
                18
                +)

              
                
                19
                +

              
                
                20
                +type Header struct {

              
                
                21
                +	ID uint16

              
                
                22
                +

              
                
                23
                +	RecursionDesired    bool

              
                
                24
                +	TruncatedMessage    bool

              
                
                25
                +	AuthoritativeAnswer bool

              
                
                26
                +	OPCode              uint8

              
                
                27
                +	Response            bool

              
                
                28
                +	Rescode             ResultCode

              
                
                29
                +	CheckingDisabled    bool

              
                
                30
                +	AuthedData          bool

              
                
                31
                +	Z                   bool

              
                
                32
                +	RecursionAvailable  bool

              
                
                33
                +

              
                
                34
                +	Questions            uint16

              
                
                35
                +	Answers              uint16

              
                
                36
                +	AuthoritativeEntries uint16

              
                
                37
                +	ResourceEntries      uint16

              
                
                38
                +}

              
                
                39
                +

              
                
                40
                +func ReadHeader(r *bytes.Reader) (Header, error) {

              
                
                41
                +	var h Header

              
                
                42
                +	if err := binary.Read(r, binary.BigEndian, &h.ID); err != nil {

              
                
                43
                +		return h, fmt.Errorf("reading ID: %w", err)

              
                
                44
                +	}

              
                
                45
                +

              
                
                46
                +	var flags uint16

              
                
                47
                +	if err := binary.Read(r, binary.BigEndian, &flags); err != nil {

              
                
                48
                +		return h, fmt.Errorf("reading flags: %w", err)

              
                
                49
                +	}

              
                
                50
                +	h.unpackFlags(flags)

              
                
                51
                +

              
                
                52
                +	if err := binary.Read(r, binary.BigEndian, &h.Questions); err != nil {

              
                
                53
                +		return h, fmt.Errorf("reading questions: %w", err)

              
                
                54
                +	}

              
                
                55
                +	if err := binary.Read(r, binary.BigEndian, &h.Answers); err != nil {

              
                
                56
                +		return h, fmt.Errorf("reading answers: %w", err)

              
                
                57
                +	}

              
                
                58
                +	if err := binary.Read(r, binary.BigEndian, &h.AuthoritativeEntries); err != nil {

              
                
                59
                +		return h, fmt.Errorf("reading auth entries: %w", err)

              
                
                60
                +	}

              
                
                61
                +	if err := binary.Read(r, binary.BigEndian, &h.ResourceEntries); err != nil {

              
                
                62
                +		return h, fmt.Errorf("reading resource entries: %w", err)

              
                
                63
                +	}

              
                
                64
                +

              
                
                65
                +	return h, nil

              
                
                66
                +}

              
                
                67
                +

              
                
                68
                +func (h *Header) unpackFlags(flags uint16) {

              
                
                69
                +	h.RecursionDesired = flags&(1<<8) != 0

              
                
                70
                +	h.TruncatedMessage = flags&(1<<9) != 0

              
                
                71
                +	h.AuthoritativeAnswer = flags&(1<<10) != 0

              
                
                72
                +	h.OPCode = uint8((flags >> 11) & 0xF)

              
                
                73
                +	h.Response = flags&(1<<15) != 0

              
                
                74
                +	h.Rescode = ResultCode(flags & 0xF)

              
                
                75
                +	h.CheckingDisabled = flags&(1<<4) != 0

              
                
                76
                +	h.AuthedData = flags&(1<<5) != 0

              
                
                77
                +	h.Z = flags&(1<<6) != 0

              
                
                78
                +	h.RecursionAvailable = flags&(1<<7) != 0

              
                
                79
                +}

              
                
                80
                +

              
                
                81
                +func (h Header) packFlags() uint16 {

              
                
                82
                +	var flags uint16

              
                
                83
                +	if h.RecursionDesired {

              
                
                84
                +		flags |= 1 << 8

              
                
                85
                +	}

              
                
                86
                +	if h.TruncatedMessage {

              
                
                87
                +		flags |= 1 << 9

              
                
                88
                +	}

              
                
                89
                +	if h.AuthoritativeAnswer {

              
                
                90
                +		flags |= 1 << 10

              
                
                91
                +	}

              
                
                92
                +	flags |= uint16(h.OPCode) << 11

              
                
                93
                +	if h.Response {

              
                
                94
                +		flags |= 1 << 15

              
                
                95
                +	}

              
                
                96
                +	flags |= uint16(h.Rescode)

              
                
                97
                +	if h.CheckingDisabled {

              
                
                98
                +		flags |= 1 << 4

              
                
                99
                +	}

              
                
                100
                +	if h.AuthedData {

              
                
                101
                +		flags |= 1 << 5

              
                
                102
                +	}

              
                
                103
                +	if h.Z {

              
                
                104
                +		flags |= 1 << 6

              
                
                105
                +	}

              
                
                106
                +	if h.RecursionAvailable {

              
                
                107
                +		flags |= 1 << 7

              
                
                108
                +	}

              
                
                109
                +	return flags

              
                
                110
                +}

              
A dns-server/main.go
···
                
                1
                +package main

              
                
                2
                +

              
                
                3
                +import (

              
                
                4
                +	_ "embed"

              
                
                5
                +	"fmt"

              
                
                6
                +)

              
                
                7
                +

              
                
                8
                +//go:embed response_packet.txt

              
                
                9
                +var respPack []byte

              
                
                10
                +

              
                
                11
                +func main() {

              
                
                12
                +	p, err := ParsePacket(respPack)

              
                
                13
                +	if err != nil {

              
                
                14
                +		panic(err)

              
                
                15
                +	}

              
                
                16
                +

              
                
                17
                +	fmt.Printf("%+v\n", p.Header)

              
                
                18
                +	for _, q := range p.Questions {

              
                
                19
                +		fmt.Printf("%+v\n", q)

              
                
                20
                +	}

              
                
                21
                +	for _, r := range p.Answers {

              
                
                22
                +		fmt.Printf("%+v\n", r)

              
                
                23
                +	}

              
                
                24
                +	for _, r := range p.Authorities {

              
                
                25
                +		fmt.Printf("%+v\n", r)

              
                
                26
                +	}

              
                
                27
                +	for _, r := range p.Resources {

              
                
                28
                +		fmt.Printf("%+v\n", r)

              
                
                29
                +	}

              
                
                30
                +}

              
A dns-server/packet.go
···
                
                1
                +package main

              
                
                2
                +

              
                
                3
                +import "bytes"

              
                
                4
                +

              
                
                5
                +type Packet struct {

              
                
                6
                +	Header      Header

              
                
                7
                +	Questions   []Question

              
                
                8
                +	Answers     []Record

              
                
                9
                +	Authorities []Record

              
                
                10
                +	Resources   []Record

              
                
                11
                +}

              
                
                12
                +

              
                
                13
                +func ParsePacket(packet []byte) (Packet, error) {

              
                
                14
                +	r := bytes.NewReader(packet)

              
                
                15
                +

              
                
                16
                +	var err error

              
                
                17
                +	var p Packet

              
                
                18
                +

              
                
                19
                +	p.Header, err = ReadHeader(r)

              
                
                20
                +	if err != nil {

              
                
                21
                +		return Packet{}, err

              
                
                22
                +	}

              
                
                23
                +

              
                
                24
                +	// TODO: don't do int(Questions) ????

              
                
                25
                +	for i := 0; i < int(p.Header.Questions); i++ {

              
                
                26
                +		q, err := ReadQuestion(r, packet)

              
                
                27
                +		if err != nil {

              
                
                28
                +			return Packet{}, err

              
                
                29
                +		}

              
                
                30
                +		p.Questions = append(p.Questions, q)

              
                
                31
                +	}

              
                
                32
                +

              
                
                33
                +	for i := 0; i < int(p.Header.Answers); i++ {

              
                
                34
                +		a, err := ReadRecord(r, packet)

              
                
                35
                +		if err != nil {

              
                
                36
                +			return Packet{}, err

              
                
                37
                +		}

              
                
                38
                +		p.Answers = append(p.Answers, a)

              
                
                39
                +	}

              
                
                40
                +

              
                
                41
                +	for i := 0; i < int(p.Header.AuthoritativeEntries); i++ {

              
                
                42
                +		ae, err := ReadRecord(r, packet)

              
                
                43
                +		if err != nil {

              
                
                44
                +			return Packet{}, err

              
                
                45
                +		}

              
                
                46
                +		p.Authorities = append(p.Authorities, ae)

              
                
                47
                +	}

              
                
                48
                +

              
                
                49
                +	for i := 0; i < int(p.Header.ResourceEntries); i++ {

              
                
                50
                +		re, err := ReadRecord(r, packet)

              
                
                51
                +		if err != nil {

              
                
                52
                +			return Packet{}, err

              
                
                53
                +		}

              
                
                54
                +		p.Resources = append(p.Resources, re)

              
                
                55
                +	}

              
                
                56
                +

              
                
                57
                +	return p, nil

              
                
                58
                +}

              
A dns-server/question.go
···
                
                1
                +package main

              
                
                2
                +

              
                
                3
                +import (

              
                
                4
                +	"bytes"

              
                
                5
                +	"encoding/binary"

              
                
                6
                +)

              
                
                7
                +

              
                
                8
                +type Question struct {

              
                
                9
                +	Name  string

              
                
                10
                +	Type  uint16

              
                
                11
                +	Class uint16

              
                
                12
                +}

              
                
                13
                +

              
                
                14
                +func ReadQuestion(r *bytes.Reader, packet []byte) (Question, error) {

              
                
                15
                +	name, err := readName(r, packet)

              
                
                16
                +	if err != nil {

              
                
                17
                +		return Question{}, err

              
                
                18
                +	}

              
                
                19
                +

              
                
                20
                +	var qtype, qclass uint16

              
                
                21
                +	_ = binary.Read(r, binary.BigEndian, &qtype)

              
                
                22
                +	_ = binary.Read(r, binary.BigEndian, &qclass)

              
                
                23
                +

              
                
                24
                +	return Question{

              
                
                25
                +		Name:  name,

              
                
                26
                +		Type:  qtype,

              
                
                27
                +		Class: qclass,

              
                
                28
                +	}, nil

              
                
                29
                +}

              
A dns-server/readme
···
                
                1
                +dns-server

              
                
                2
                +----------

              
                
                3
                +

              
                
                4
                +Mainly me going through: <github.com/EmilHernvall/dnsguide>

              
A dns-server/record.go
···
                
                1
                +package main

              
                
                2
                +

              
                
                3
                +import (

              
                
                4
                +	"bytes"

              
                
                5
                +	"encoding/binary"

              
                
                6
                +	"fmt"

              
                
                7
                +	"strings"

              
                
                8
                +)

              
                
                9
                +

              
                
                10
                +type Record struct {

              
                
                11
                +	Name  string

              
                
                12
                +	Type  uint16

              
                
                13
                +	Class uint16

              
                
                14
                +	TTL   uint32

              
                
                15
                +	Data  string

              
                
                16
                +}

              
                
                17
                +

              
                
                18
                +func ReadRecord(r *bytes.Reader, packet []byte) (Record, error) {

              
                
                19
                +	name, err := readName(r, packet)

              
                
                20
                +	if err != nil {

              
                
                21
                +		return Record{}, err

              
                
                22
                +	}

              
                
                23
                +

              
                
                24
                +	var rtype, class, rdlen uint16

              
                
                25
                +	var ttl uint32

              
                
                26
                +	_ = binary.Read(r, binary.BigEndian, &rtype)

              
                
                27
                +	_ = binary.Read(r, binary.BigEndian, &class)

              
                
                28
                +	_ = binary.Read(r, binary.BigEndian, &ttl)

              
                
                29
                +	_ = binary.Read(r, binary.BigEndian, &rdlen)

              
                
                30
                +

              
                
                31
                +	var data string

              
                
                32
                +	switch rtype {

              
                
                33
                +	case 1: // A

              
                
                34
                +		var ip [4]byte

              
                
                35
                +		_, _ = r.Read(ip[:])

              
                
                36
                +		data = fmt.Sprintf("%d.%d.%d.%d",

              
                
                37
                +			ip[0], ip[1], ip[2], ip[3])

              
                
                38
                +

              
                
                39
                +	default:

              
                
                40
                +		buf := make([]byte, rdlen)

              
                
                41
                +		_, _ = r.Read(buf)

              
                
                42
                +		data = fmt.Sprintf("%x", buf)

              
                
                43
                +	}

              
                
                44
                +

              
                
                45
                +	return Record{

              
                
                46
                +		Name:  name,

              
                
                47
                +		Type:  rtype,

              
                
                48
                +		Class: class,

              
                
                49
                +		TTL:   ttl,

              
                
                50
                +		Data:  data,

              
                
                51
                +	}, nil

              
                
                52
                +}

              
                
                53
                +

              
                
                54
                +func readName(r *bytes.Reader, packet []byte) (string, error) {

              
                
                55
                +	var labels []string

              
                
                56
                +	for {

              
                
                57
                +		length, err := r.ReadByte()

              
                
                58
                +		if err != nil {

              
                
                59
                +			return "", err

              
                
                60
                +		}

              
                
                61
                +		if length == 0 {

              
                
                62
                +			break

              
                
                63
                +		}

              
                
                64
                +		// pointer: top two bits set (0xC0)

              
                
                65
                +		if length&0xC0 == 0xC0 {

              
                
                66
                +			low, err := r.ReadByte()

              
                
                67
                +			if err != nil {

              
                
                68
                +				return "", err

              
                
                69
                +			}

              
                
                70
                +			offset := int(uint16(length&0x3F)<<8 | uint16(low))

              
                
                71
                +			sub := bytes.NewReader(packet[offset:])

              
                
                72
                +			name, err := readName(sub, packet)

              
                
                73
                +			if err != nil {

              
                
                74
                +				return "", err

              
                
                75
                +			}

              
                
                76
                +			labels = append(labels, name)

              
                
                77
                +			break // pointer always ends the name

              
                
                78
                +		}

              
                
                79
                +		buf := make([]byte, length)

              
                
                80
                +		if _, err := r.Read(buf); err != nil {

              
                
                81
                +			return "", err

              
                
                82
                +		}

              
                
                83
                +		labels = append(labels, string(buf))

              
                
                84
                +	}

              
                
                85
                +	return strings.Join(labels, "."), nil

              
                
                86
                +}

              
A dns-server/response_packet.txt

Not showing binary file.