1 static bool
is_digit(char c)2 is_digit(char c)
3 {
4 if (c >= '0' && c <= '9')
5 return (true);
6 return (false);
7 }
8
9 static wdns_res
_wdns_str_to_name(const char * str,wdns_name_t * name,bool downcase)10 _wdns_str_to_name(const char *str, wdns_name_t *name, bool downcase)
11 {
12 const char *p;
13 size_t label_len;
14 ssize_t slen;
15 uint8_t c, *oclen, *data;
16 wdns_res res;
17
18 res = wdns_res_parse_error;
19
20 p = str;
21 slen = strlen(str);
22
23 if (slen == 1 && *p == '.') {
24 name->len = 1;
25 name->data = my_malloc(1);
26 name->data[0] = '\0';
27 return (wdns_res_success);
28 }
29
30 name->len = 0;
31 name->data = my_malloc(WDNS_MAXLEN_NAME);
32
33 data = name->data;
34 label_len = 0;
35 oclen = data++;
36 name->len++;
37
38 for (;;) {
39 c = *p++;
40 label_len++;
41
42 if (slen == 0) {
43 /* end of input */
44 if (name->len == WDNS_MAXLEN_NAME) {
45 res = wdns_res_name_overflow;
46 goto out;
47 }
48 *oclen = --label_len;
49 *data++ = '\0';
50 name->len++;
51 break;
52 }
53
54 if (name->len >= WDNS_MAXLEN_NAME) {
55 res = wdns_res_name_overflow;
56 goto out;
57 }
58
59 if (c >= 'A' && c <= 'Z') {
60 /* an upper case letter; downcase it */
61 if (downcase)
62 c |= 0x20;
63 *data++ = c;
64 name->len++;
65 } else if (c == '\\' && !is_digit(*p)) {
66 /* an escaped character */
67 if (slen <= 0)
68 goto out;
69 *data++ = *p;
70 name->len++;
71 p++;
72 slen--;
73 } else if (c == '\\' && slen >= 3) {
74 /* an escaped octet */
75 char d[4];
76 char *endptr = NULL;
77 long int val;
78
79 d[0] = *p++;
80 d[1] = *p++;
81 d[2] = *p++;
82 d[3] = '\0';
83 slen -= 3;
84 if (!is_digit(d[0]) || !is_digit(d[1]) || !is_digit(d[2]))
85 goto out;
86 val = strtol(d, &endptr, 10);
87 if (endptr != NULL && *endptr == '\0'
88 && val >= 0 && val <= 255)
89 {
90 uint8_t uval;
91
92 uval = (uint8_t) val;
93 *data++ = uval;
94 name->len++;
95 } else {
96 goto out;
97 }
98 } else if (c == '\\') {
99 /* should not occur */
100 goto out;
101 } else if (c == '.') {
102 /* end of label */
103 *oclen = --label_len;
104 if (label_len == 0)
105 goto out;
106 oclen = data++;
107 if (slen > 1)
108 name->len++;
109 label_len = 0;
110 } else if (c != '\0') {
111 *data++ = c;
112 name->len++;
113 }
114
115 slen--;
116 }
117
118 return (wdns_res_success);
119
120 out:
121 my_free(name->data);
122 return (res);
123 }
124
125 wdns_res
wdns_str_to_name(const char * str,wdns_name_t * name)126 wdns_str_to_name(const char *str, wdns_name_t *name)
127 {
128 return _wdns_str_to_name(str, name, true);
129 }
130
131 wdns_res
wdns_str_to_name_case(const char * str,wdns_name_t * name)132 wdns_str_to_name_case(const char *str, wdns_name_t *name)
133 {
134 return _wdns_str_to_name(str, name, false);
135 }
136