1 static wdns_res
gen_label_offsets(wdns_name_t * name,size_t n_labels,uint8_t * offsets)2 gen_label_offsets(wdns_name_t *name, size_t n_labels, uint8_t *offsets)
3 {
4 size_t n = 0;
5 uint8_t c, *data;
6
7 data = name->data;
8
9 while ((c = *data) != 0) {
10 if (c <= 63) {
11 offsets[n++] = data - name->data;
12 if (n == n_labels)
13 return (wdns_res_success);
14 data += c;
15 if (data - name->data > name->len)
16 return (wdns_res_name_overflow);
17 } else {
18 return (wdns_res_invalid_length_octet);
19 }
20 data++;
21 }
22 return (wdns_res_success);
23 }
24
25 static bool
compare_label(uint8_t * l0,uint8_t * l1)26 compare_label(uint8_t *l0, uint8_t *l1)
27 {
28 uint8_t len0, len1;
29 len0 = *l0++;
30 len1 = *l1++;
31 if (len0 == len1)
32 return (memcmp(l0, l1, len0) == 0);
33 return (false);
34 }
35
36 /**
37 * Determine if a name is a subdomain of another domain.
38 *
39 * A domain is not a subdomain of itself.
40 *
41 * \param[in] n0
42 * \param[in] n1
43 * \param[out] is_subdomain
44 *
45 * \return wdns_res_success
46 * \return wdns_res_parse_error
47 */
48
49 wdns_res
wdns_is_subdomain(wdns_name_t * n0,wdns_name_t * n1,bool * is_subdomain)50 wdns_is_subdomain(wdns_name_t *n0, wdns_name_t *n1, bool *is_subdomain)
51 {
52 wdns_res res;
53 size_t n0_nlabels, n1_nlabels;
54 ssize_t n0_idx, n1_idx;
55
56 *is_subdomain = false;
57
58 /* count the number of labels in each name */
59 res = wdns_count_labels(n0, &n0_nlabels);
60 if (res != wdns_res_success)
61 return (wdns_res_parse_error);
62
63 res = wdns_count_labels(n1, &n1_nlabels);
64 if (res != wdns_res_success)
65 return (wdns_res_parse_error);
66
67 /* exclude any cases that can be determined solely by label counts */
68 if (n0_nlabels <= n1_nlabels) {
69 /* a subdomain must have more labels than any of its parents */
70 return (wdns_res_success);
71 }
72 if (n0_nlabels == 0) {
73 /* the root cannot be a subdomain of any other domain */
74 return (wdns_res_success);
75 }
76 if (n1_nlabels == 0) {
77 /* all other domains are subdomains of the root */
78 *is_subdomain = true;
79 return (wdns_res_success);
80 }
81
82 /* for each name, create an array of label offsets */
83 uint8_t n0_offsets[n0_nlabels];
84 uint8_t n1_offsets[n1_nlabels];
85 memset(n0_offsets, 0, sizeof(n0_offsets));
86 memset(n1_offsets, 0, sizeof(n1_offsets));
87
88 res = gen_label_offsets(n0, n0_nlabels, n0_offsets);
89 if (res != wdns_res_success)
90 return (wdns_res_parse_error);
91
92 res = gen_label_offsets(n1, n1_nlabels, n1_offsets);
93 if (res != wdns_res_success)
94 return (wdns_res_parse_error);
95
96 /* compare each label, right-to-left */
97 n0_idx = n0_nlabels - 1;
98 n1_idx = n1_nlabels - 1;
99 do {
100 if (!compare_label(n0->data + n0_offsets[n0_idx],
101 n1->data + n1_offsets[n1_idx]))
102 {
103 return (wdns_res_success);
104 }
105 n0_idx--;
106 n1_idx--;
107 } while (n1_idx >= 0);
108
109 /* all labels of the potential parent domain have compared true,
110 * thus n1 is a suffix of n0 */
111 *is_subdomain = true;
112 return (wdns_res_success);
113 }
114