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
Authored at: 2026-03-20 00:14:00 +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.