all repos

scratch @ bc17d480554cde516be3fa2adc55455aadfebc1a

⭐ me doing recreational ~~drugs~~ programming
6 files changed, 141 insertions(+), 12 deletions(-)
dns: ch2
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-03-21 13:25:41 +0200
Change ID: umpoxznltvsykxqvlnkpvokwmrrxwyql
Parent: 77539db
M dns-server/header.go
···
                6
                6
                 	"fmt"

              
                7
                7
                 )

              
                8
                8
                 

              
                9
                
                -type ResultCode uint

              
                
                9
                +type ResultCode = uint8

              
                10
                10
                 

              
                11
                11
                 const (

              
                12
                12
                 	NOERROR ResultCode = iota

              ···
                65
                65
                 	return h, nil

              
                66
                66
                 }

              
                67
                67
                 

              
                
                68
                +func (h *Header) Write(b *bytes.Buffer) error {

              
                
                69
                +	_ = binary.Write(b, binary.BigEndian, h.ID)

              
                
                70
                +

              
                
                71
                +	_ = b.WriteByte((b2u8(h.RecursionDesired)) |

              
                
                72
                +		(b2u8(h.TruncatedMessage) << 1) |

              
                
                73
                +		(b2u8(h.AuthoritativeAnswer) << 2) |

              
                
                74
                +		(h.OPCode << 3) |

              
                
                75
                +		(b2u8(h.Response) << 7))

              
                
                76
                +

              
                
                77
                +	_ = b.WriteByte(h.Rescode |

              
                
                78
                +		(b2u8(h.CheckingDisabled) << 4) |

              
                
                79
                +		(b2u8(h.AuthedData) << 5) |

              
                
                80
                +		(b2u8(h.Z) << 6) |

              
                
                81
                +		(b2u8(h.RecursionAvailable) << 7))

              
                
                82
                +

              
                
                83
                +	_ = binary.Write(b, binary.BigEndian, h.Questions)

              
                
                84
                +	_ = binary.Write(b, binary.BigEndian, h.Answers)

              
                
                85
                +	_ = binary.Write(b, binary.BigEndian, h.AuthoritativeEntries)

              
                
                86
                +	_ = binary.Write(b, binary.BigEndian, h.ResourceEntries)

              
                
                87
                +	return nil

              
                
                88
                +}

              
                
                89
                +

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

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

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

              ···
                108
                130
                 	}

              
                109
                131
                 	return flags

              
                110
                132
                 }

              
                
                133
                +

              
                
                134
                +func b2u8(b bool) uint8 {

              
                
                135
                +	if b {

              
                
                136
                +		return 1

              
                
                137
                +	}

              
                
                138
                +	return 0

              
                
                139
                +}

              
M dns-server/main.go
···
                1
                1
                 package main

              
                2
                2
                 

              
                3
                3
                 import (

              
                
                4
                +	"bytes"

              
                4
                5
                 	_ "embed"

              
                5
                6
                 	"fmt"

              
                
                7
                +	"net"

              
                6
                8
                 )

              
                7
                9
                 

              
                8
                
                -//go:embed response_packet.txt

              
                9
                
                -var respPack []byte

              
                
                10
                +func main() {

              
                
                11
                +	qname := "google.com"

              
                
                12
                +	server := "8.8.8.8:53"

              
                
                13
                +

              
                
                14
                +	conn, _ := net.Dial("udp", server)

              
                
                15
                +	defer conn.Close()

              
                
                16
                +

              
                
                17
                +	p := Packet{}

              
                
                18
                +	p.Header.ID = 6666

              
                
                19
                +	p.Header.RecursionDesired = true

              
                
                20
                +	p.Questions = append(p.Questions, Question{

              
                
                21
                +		Name:  qname,

              
                
                22
                +		Type:  1, // A

              
                
                23
                +		Class: 1, // IN

              
                
                24
                +	})

              
                
                25
                +

              
                
                26
                +	buf := &bytes.Buffer{}

              
                
                27
                +	if err := p.Write(buf); err != nil {

              
                
                28
                +		fmt.Printf("failed to write packet: %v", err)

              
                
                29
                +	}

              
                
                30
                +

              
                
                31
                +	if _, err := conn.Write(buf.Bytes()); err != nil {

              
                
                32
                +		fmt.Printf("failed to write to connection: %v", err)

              
                
                33
                +	}

              
                10
                34
                 

              
                11
                
                -func main() {

              
                12
                
                -	p, err := ParsePacket(respPack)

              
                
                35
                +	res := make([]byte, 512)

              
                
                36
                +	n, err := conn.Read(res)

              
                13
                37
                 	if err != nil {

              
                14
                
                -		panic(err)

              
                
                38
                +		fmt.Printf("failed to read from connection: %v", err)

              
                15
                39
                 	}

              
                16
                40
                 

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

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

              
                
                41
                +	resPack, err := ParsePacket(res[:n])

              
                
                42
                +	if err != nil {

              
                
                43
                +		fmt.Printf("failed to parse packet: %v", err)

              
                
                44
                +	}

              
                
                45
                +

              
                
                46
                +	fmt.Printf("%+v\n", resPack.Header)

              
                
                47
                +	for _, q := range resPack.Questions {

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

              
                20
                49
                 	}

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

              
                
                50
                +	for _, r := range resPack.Answers {

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

              
                23
                52
                 	}

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

              
                
                53
                +	for _, r := range resPack.Authorities {

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

              
                26
                55
                 	}

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

              
                
                56
                +	for _, r := range resPack.Resources {

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

              
                29
                58
                 	}

              
                30
                59
                 }

              
M dns-server/packet.go
···
                21
                21
                 		return Packet{}, err

              
                22
                22
                 	}

              
                23
                23
                 

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

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

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

              
                27
                26
                 		if err != nil {

              ···
                56
                55
                 

              
                57
                56
                 	return p, nil

              
                58
                57
                 }

              
                
                58
                +

              
                
                59
                +func (p *Packet) Write(b *bytes.Buffer) error {

              
                
                60
                +	p.Header.Questions = uint16(len(p.Questions))

              
                
                61
                +	p.Header.Answers = uint16(len(p.Answers))

              
                
                62
                +	p.Header.AuthoritativeEntries = uint16(len(p.Authorities))

              
                
                63
                +	p.Header.ResourceEntries = uint16(len(p.Resources))

              
                
                64
                +	_ = p.Header.Write(b)

              
                
                65
                +

              
                
                66
                +	for i := range p.Questions {

              
                
                67
                +		_ = p.Questions[i].Write(b)

              
                
                68
                +	}

              
                
                69
                +

              
                
                70
                +	for i := range p.Answers {

              
                
                71
                +		_, _ = p.Answers[i].Write(b)

              
                
                72
                +	}

              
                
                73
                +

              
                
                74
                +	for i := range p.Authorities {

              
                
                75
                +		_, _ = p.Authorities[i].Write(b)

              
                
                76
                +	}

              
                
                77
                +

              
                
                78
                +	for i := range p.Resources {

              
                
                79
                +		_, _ = p.Resources[i].Write(b)

              
                
                80
                +	}

              
                
                81
                +

              
                
                82
                +	return nil

              
                
                83
                +}

              
M dns-server/question.go
···
                27
                27
                 		Class: qclass,

              
                28
                28
                 	}, nil

              
                29
                29
                 }

              
                
                30
                +

              
                
                31
                +func (q Question) Write(b *bytes.Buffer) error {

              
                
                32
                +	_ = writeName(b, q.Name)

              
                
                33
                +	_ = binary.Write(b, binary.BigEndian, q.Type)

              
                
                34
                +	_ = binary.Write(b, binary.BigEndian, q.Class)

              
                
                35
                +	return nil

              
                
                36
                +}

              
M dns-server/record.go
···
                4
                4
                 	"bytes"

              
                5
                5
                 	"encoding/binary"

              
                6
                6
                 	"fmt"

              
                
                7
                +	"net"

              
                7
                8
                 	"strings"

              
                8
                9
                 )

              
                9
                10
                 

              ···
                51
                52
                 	}, nil

              
                52
                53
                 }

              
                53
                54
                 

              
                
                55
                +func (r Record) Write(b *bytes.Buffer) (int, error) {

              
                
                56
                +	start := b.Len()

              
                
                57
                +	switch r.Type {

              
                
                58
                +	case 1: // A

              
                
                59
                +		_ = writeName(b, r.Name)

              
                
                60
                +		_ = binary.Write(b, binary.BigEndian, r.Type)

              
                
                61
                +		_ = binary.Write(b, binary.BigEndian, r.Class)

              
                
                62
                +		_ = binary.Write(b, binary.BigEndian, r.TTL)

              
                
                63
                +		_ = binary.Write(b, binary.BigEndian, uint16(4))

              
                
                64
                +

              
                
                65
                +		ip := net.ParseIP(r.Data).To4()

              
                
                66
                +		if ip == nil {

              
                
                67
                +			return 0, fmt.Errorf("invalid IPv4 address: %s", r.Data)

              
                
                68
                +		}

              
                
                69
                +

              
                
                70
                +		_, _ = b.Write(ip)

              
                
                71
                +

              
                
                72
                +	default:

              
                
                73
                +		fmt.Printf("Skipping record: %+v\n", r)

              
                
                74
                +	}

              
                
                75
                +

              
                
                76
                +	return b.Len() - start, nil

              
                
                77
                +}

              
                
                78
                +

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

              
                55
                80
                 	var labels []string

              
                56
                81
                 	for {

              ···
                84
                109
                 	}

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

              
                86
                111
                 }

              
                
                112
                +

              
                
                113
                +// TODO: wrap the Buffer, to have the len == 512 guard

              
                
                114
                +func writeName(w *bytes.Buffer, qname string) error {

              
                
                115
                +	for label := range strings.SplitSeq(qname, ".") {

              
                
                116
                +		llen := len(label)

              
                
                117
                +		if llen > 0x3f {

              
                
                118
                +			return fmt.Errorf("single label exceeds 63 characters of length")

              
                
                119
                +		}

              
                
                120
                +		_ = w.WriteByte(byte(llen))

              
                
                121
                +		_, _ = w.Write([]byte(label))

              
                
                122
                +	}

              
                
                123
                +	_ = w.WriteByte(0)

              
                
                124
                +	return nil

              
                
                125
                +}

              
D dns-server/response_packet.txt

Not showing binary file.