6 files changed,
141 insertions(+),
12 deletions(-)
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/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 +}