Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | /*! \file */ |
15 | | |
16 | | #include <ctype.h> |
17 | | #include <errno.h> |
18 | | #include <inttypes.h> |
19 | | #include <stdbool.h> |
20 | | #include <stdio.h> |
21 | | #include <stdlib.h> |
22 | | |
23 | | #include <isc/ascii.h> |
24 | | #include <isc/buffer.h> |
25 | | #include <isc/parseint.h> |
26 | | #include <isc/region.h> |
27 | | #include <isc/result.h> |
28 | | #include <isc/string.h> |
29 | | #include <isc/util.h> |
30 | | |
31 | | #include <dns/ttl.h> |
32 | | |
33 | | static isc_result_t |
34 | | bind_ttl(isc_textregion_t *source, uint32_t *ttl); |
35 | | |
36 | | /* |
37 | | * Helper for dns_ttl_totext(). |
38 | | */ |
39 | | static isc_result_t |
40 | | ttlfmt(unsigned int t, const char *s, bool verbose, bool space, |
41 | 104k | isc_buffer_t *target) { |
42 | 104k | char tmp[60]; |
43 | 104k | unsigned int len; |
44 | 104k | isc_region_t region; |
45 | | |
46 | 104k | if (verbose) { |
47 | 104k | len = snprintf(tmp, sizeof(tmp), "%s%u %s%s", space ? " " : "", |
48 | 104k | t, s, t == 1 ? "" : "s"); |
49 | 104k | } else { |
50 | 0 | len = snprintf(tmp, sizeof(tmp), "%u%c", t, s[0]); |
51 | 0 | } |
52 | | |
53 | 104k | INSIST(len + 1 <= sizeof(tmp)); |
54 | 104k | isc_buffer_availableregion(target, ®ion); |
55 | 104k | if (len > region.length) { |
56 | 0 | return ISC_R_NOSPACE; |
57 | 0 | } |
58 | 104k | memmove(region.base, tmp, len); |
59 | 104k | isc_buffer_add(target, len); |
60 | | |
61 | 104k | return ISC_R_SUCCESS; |
62 | 104k | } |
63 | | |
64 | | /* |
65 | | * Derived from bind8 ns_format_ttl(). |
66 | | */ |
67 | | isc_result_t |
68 | 27.5k | dns_ttl_totext(uint32_t src, bool verbose, bool upcase, isc_buffer_t *target) { |
69 | 27.5k | unsigned int secs, mins, hours, days, weeks, x; |
70 | | |
71 | 27.5k | secs = src % 60; |
72 | 27.5k | src /= 60; |
73 | 27.5k | mins = src % 60; |
74 | 27.5k | src /= 60; |
75 | 27.5k | hours = src % 24; |
76 | 27.5k | src /= 24; |
77 | 27.5k | days = src % 7; |
78 | 27.5k | src /= 7; |
79 | 27.5k | weeks = src; |
80 | 27.5k | src = 0; |
81 | 27.5k | POST(src); |
82 | | |
83 | 27.5k | x = 0; |
84 | 27.5k | if (weeks != 0) { |
85 | 17.9k | RETERR(ttlfmt(weeks, "week", verbose, x > 0, target)); |
86 | 17.9k | x++; |
87 | 17.9k | } |
88 | 27.5k | if (days != 0) { |
89 | 16.4k | RETERR(ttlfmt(days, "day", verbose, x > 0, target)); |
90 | 16.4k | x++; |
91 | 16.4k | } |
92 | 27.5k | if (hours != 0) { |
93 | 23.7k | RETERR(ttlfmt(hours, "hour", verbose, x > 0, target)); |
94 | 23.7k | x++; |
95 | 23.7k | } |
96 | 27.5k | if (mins != 0) { |
97 | 24.0k | RETERR(ttlfmt(mins, "minute", verbose, x > 0, target)); |
98 | 24.0k | x++; |
99 | 24.0k | } |
100 | 27.5k | if (secs != 0 || (weeks == 0 && days == 0 && hours == 0 && mins == 0)) { |
101 | 22.3k | RETERR(ttlfmt(secs, "second", verbose, x > 0, target)); |
102 | 22.3k | x++; |
103 | 22.3k | } |
104 | 27.5k | INSIST(x > 0); |
105 | | /* |
106 | | * If only a single unit letter is printed, print it |
107 | | * in upper case. (Why? Because BIND 8 does that. |
108 | | * Presumably it has a reason.) |
109 | | */ |
110 | 27.5k | if (x == 1 && upcase && !verbose) { |
111 | 0 | isc_region_t region; |
112 | | /* |
113 | | * The unit letter is the last character in the |
114 | | * used region of the buffer. |
115 | | */ |
116 | 0 | isc_buffer_usedregion(target, ®ion); |
117 | 0 | region.base[region.length - 1] = |
118 | 0 | isc_ascii_toupper(region.base[region.length - 1]); |
119 | 0 | } |
120 | 27.5k | return ISC_R_SUCCESS; |
121 | 27.5k | } |
122 | | |
123 | | isc_result_t |
124 | 5.03k | dns_counter_fromtext(isc_textregion_t *source, uint32_t *ttl) { |
125 | 5.03k | return bind_ttl(source, ttl); |
126 | 5.03k | } |
127 | | |
128 | | isc_result_t |
129 | 269k | dns_ttl_fromtext(isc_textregion_t *source, uint32_t *ttl) { |
130 | 269k | isc_result_t result; |
131 | | |
132 | 269k | result = bind_ttl(source, ttl); |
133 | 269k | if (result != ISC_R_SUCCESS && result != ISC_R_RANGE) { |
134 | 244k | result = DNS_R_BADTTL; |
135 | 244k | } |
136 | 269k | return result; |
137 | 269k | } |
138 | | |
139 | | static isc_result_t |
140 | 274k | bind_ttl(isc_textregion_t *source, uint32_t *ttl) { |
141 | 274k | uint64_t tmp = 0ULL; |
142 | 274k | uint32_t n; |
143 | 274k | char *s; |
144 | 274k | char buf[64]; |
145 | 274k | char nbuf[64]; /* Number buffer */ |
146 | | |
147 | | /* |
148 | | * Copy the buffer as it may not be NULL terminated. |
149 | | * No legal counter / ttl is longer that 63 characters. |
150 | | */ |
151 | 274k | if (source->length > sizeof(buf) - 1) { |
152 | 279 | return DNS_R_SYNTAX; |
153 | 279 | } |
154 | | /* Copy source->length bytes and NUL terminate. */ |
155 | 274k | snprintf(buf, sizeof(buf), "%.*s", (int)source->length, source->base); |
156 | 274k | s = buf; |
157 | | |
158 | 275k | do { |
159 | 275k | isc_result_t result; |
160 | | |
161 | 275k | char *np = nbuf; |
162 | 333k | while (*s != '\0' && isdigit((unsigned char)*s)) { |
163 | 57.2k | *np++ = *s++; |
164 | 57.2k | } |
165 | 275k | *np++ = '\0'; |
166 | 275k | INSIST(np - nbuf <= (int)sizeof(nbuf)); |
167 | 275k | result = isc_parse_uint32(&n, nbuf, 10); |
168 | 275k | if (result != ISC_R_SUCCESS) { |
169 | 243k | return DNS_R_SYNTAX; |
170 | 243k | } |
171 | 32.2k | switch (*s) { |
172 | 359 | case 'w': |
173 | 674 | case 'W': |
174 | 674 | tmp += (uint64_t)n * 7 * 24 * 3600; |
175 | 674 | s++; |
176 | 674 | break; |
177 | 327 | case 'd': |
178 | 1.96k | case 'D': |
179 | 1.96k | tmp += (uint64_t)n * 24 * 3600; |
180 | 1.96k | s++; |
181 | 1.96k | break; |
182 | 281 | case 'h': |
183 | 548 | case 'H': |
184 | 548 | tmp += (uint64_t)n * 3600; |
185 | 548 | s++; |
186 | 548 | break; |
187 | 326 | case 'm': |
188 | 639 | case 'M': |
189 | 639 | tmp += (uint64_t)n * 60; |
190 | 639 | s++; |
191 | 639 | break; |
192 | 309 | case 's': |
193 | 748 | case 'S': |
194 | 748 | tmp += (uint64_t)n; |
195 | 748 | s++; |
196 | 748 | break; |
197 | 27.5k | case '\0': |
198 | | /* Plain number? */ |
199 | 27.5k | if (tmp != 0ULL) { |
200 | 79 | return DNS_R_SYNTAX; |
201 | 79 | } |
202 | 27.4k | tmp = n; |
203 | 27.4k | break; |
204 | 84 | default: |
205 | 84 | return DNS_R_SYNTAX; |
206 | 32.2k | } |
207 | 32.2k | } while (*s != '\0'); |
208 | | |
209 | 30.5k | if (tmp > 0xffffffffULL) { |
210 | 24 | return ISC_R_RANGE; |
211 | 24 | } |
212 | | |
213 | 30.4k | *ttl = (uint32_t)(tmp & 0xffffffffUL); |
214 | 30.4k | return ISC_R_SUCCESS; |
215 | 30.5k | } |