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] }