summaryrefslogtreecommitdiff
path: root/internal/dns/name.go
blob: 799e53ae2058c754fdf706cb6653ac97e3cae048 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package dns

import (
	"errors"
	"strings"
)

// https://datatracker.ietf.org/doc/html/rfc9499#section-2-1.16.1.2
// ex: "www.example.com" "03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00"
type Name struct {
	Data []byte
}

func Fqdn(s string) string {
	if len(s) == 0 {
		return "."
	}
	if s[len(s)-1] == '.' {
		return s
	}
	return s + "."
}

func NewName(s string) (Name, error) {
	if s == "" || s == "." {
		return Name{Data: []byte{0}}, nil
	}
	s = Fqdn(s)
	labels := strings.Split(s, ".")
	labels = labels[:len(labels)-1]

	var b []byte
	for _, label := range labels {
		// https://datatracker.ietf.org/doc/html/rfc1034#section-3.1
		if len(label) > 63 {
			return Name{}, errors.New("dns: label > 63 octets")
		}
		b = append(b, byte(len(label)))
		b = append(b, label...)
	}
	b = append(b, 0)

	// https: //datatracker.ietf.org/doc/html/rfc1034#section-3.1
	if len(b) > 255 {
		return Name{}, errors.New("dns: name > 255 octets")
	}
	return Name{Data: b}, nil
}

func (n Name) String() string {
	if len(n.Data) == 1 && n.Data[0] == 0 {
		return "."
	}
	var labels []string
	off := 0
	for off < len(n.Data) {
		l := int(n.Data[off])
		if l == 0 {
			break
		}
		labels = append(labels, string(n.Data[off+1:off+1+l]))
		off += 1 + 1
	}
	return strings.Join(labels, ".") + "."
}

func SplitDomainName(s string) []string {
	s = Fqdn(s)
	if s == "." {
		return nil
	}
	labels := strings.Split(s, ".")
	return labels[:len(labels)-1]
}