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 | 101k | isc_buffer_t *target) { |
42 | 101k | char tmp[60]; |
43 | 101k | unsigned int len; |
44 | 101k | isc_region_t region; |
45 | | |
46 | 101k | if (verbose) { |
47 | 101k | len = snprintf(tmp, sizeof(tmp), "%s%u %s%s", space ? " " : "", |
48 | 101k | t, s, t == 1 ? "" : "s"); |
49 | 101k | } else { |
50 | 0 | len = snprintf(tmp, sizeof(tmp), "%u%c", t, s[0]); |
51 | 0 | } |
52 | | |
53 | 101k | INSIST(len + 1 <= sizeof(tmp)); |
54 | 101k | isc_buffer_availableregion(target, ®ion); |
55 | 101k | if (len > region.length) { |
56 | 0 | return ISC_R_NOSPACE; |
57 | 0 | } |
58 | 101k | memmove(region.base, tmp, len); |
59 | 101k | isc_buffer_add(target, len); |
60 | | |
61 | 101k | return ISC_R_SUCCESS; |
62 | 101k | } |
63 | | |
64 | | /* |
65 | | * Derived from bind8 ns_format_ttl(). |
66 | | */ |
67 | | isc_result_t |
68 | 27.4k | dns_ttl_totext(uint32_t src, bool verbose, bool upcase, isc_buffer_t *target) { |
69 | 27.4k | unsigned int secs, mins, hours, days, weeks, x; |
70 | | |
71 | 27.4k | secs = src % 60; |
72 | 27.4k | src /= 60; |
73 | 27.4k | mins = src % 60; |
74 | 27.4k | src /= 60; |
75 | 27.4k | hours = src % 24; |
76 | 27.4k | src /= 24; |
77 | 27.4k | days = src % 7; |
78 | 27.4k | src /= 7; |
79 | 27.4k | weeks = src; |
80 | 27.4k | src = 0; |
81 | 27.4k | POST(src); |
82 | | |
83 | 27.4k | x = 0; |
84 | 27.4k | if (weeks != 0) { |
85 | 17.8k | RETERR(ttlfmt(weeks, "week", verbose, x > 0, target)); |
86 | 17.8k | x++; |
87 | 17.8k | } |
88 | 27.4k | if (days != 0) { |
89 | 14.7k | RETERR(ttlfmt(days, "day", verbose, x > 0, target)); |
90 | 14.7k | x++; |
91 | 14.7k | } |
92 | 27.4k | if (hours != 0) { |
93 | 22.8k | RETERR(ttlfmt(hours, "hour", verbose, x > 0, target)); |
94 | 22.8k | x++; |
95 | 22.8k | } |
96 | 27.4k | if (mins != 0) { |
97 | 23.2k | RETERR(ttlfmt(mins, "minute", verbose, x > 0, target)); |
98 | 23.2k | x++; |
99 | 23.2k | } |
100 | 27.4k | if (secs != 0 || (weeks == 0 && days == 0 && hours == 0 && mins == 0)) { |
101 | 23.2k | RETERR(ttlfmt(secs, "second", verbose, x > 0, target)); |
102 | 23.2k | x++; |
103 | 23.2k | } |
104 | 27.4k | 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.4k | 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.4k | return ISC_R_SUCCESS; |
121 | 27.4k | } |
122 | | |
123 | | isc_result_t |
124 | 5.04k | dns_counter_fromtext(isc_textregion_t *source, uint32_t *ttl) { |
125 | 5.04k | return bind_ttl(source, ttl); |
126 | 5.04k | } |
127 | | |
128 | | isc_result_t |
129 | 204k | dns_ttl_fromtext(isc_textregion_t *source, uint32_t *ttl) { |
130 | 204k | isc_result_t result; |
131 | | |
132 | 204k | result = bind_ttl(source, ttl); |
133 | 204k | if (result != ISC_R_SUCCESS && result != ISC_R_RANGE) { |
134 | 179k | result = DNS_R_BADTTL; |
135 | 179k | } |
136 | 204k | return result; |
137 | 204k | } |
138 | | |
139 | | static isc_result_t |
140 | 209k | bind_ttl(isc_textregion_t *source, uint32_t *ttl) { |
141 | 209k | uint64_t tmp = 0ULL; |
142 | 209k | uint32_t n; |
143 | 209k | char *s; |
144 | 209k | char buf[64]; |
145 | 209k | 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 | 209k | if (source->length > sizeof(buf) - 1) { |
152 | 257 | return DNS_R_SYNTAX; |
153 | 257 | } |
154 | | /* Copy source->length bytes and NUL terminate. */ |
155 | 209k | snprintf(buf, sizeof(buf), "%.*s", (int)source->length, source->base); |
156 | 209k | s = buf; |
157 | | |
158 | 210k | do { |
159 | 210k | isc_result_t result; |
160 | | |
161 | 210k | char *np = nbuf; |
162 | 265k | while (*s != '\0' && isdigit((unsigned char)*s)) { |
163 | 55.0k | *np++ = *s++; |
164 | 55.0k | } |
165 | 210k | *np++ = '\0'; |
166 | 210k | INSIST(np - nbuf <= (int)sizeof(nbuf)); |
167 | 210k | result = isc_parse_uint32(&n, nbuf, 10); |
168 | 210k | if (result != ISC_R_SUCCESS) { |
169 | 178k | return DNS_R_SYNTAX; |
170 | 178k | } |
171 | 31.7k | switch (*s) { |
172 | 344 | case 'w': |
173 | 648 | case 'W': |
174 | 648 | tmp += (uint64_t)n * 7 * 24 * 3600; |
175 | 648 | s++; |
176 | 648 | break; |
177 | 320 | case 'd': |
178 | 2.60k | case 'D': |
179 | 2.60k | tmp += (uint64_t)n * 24 * 3600; |
180 | 2.60k | s++; |
181 | 2.60k | break; |
182 | 277 | case 'h': |
183 | 725 | case 'H': |
184 | 725 | tmp += (uint64_t)n * 3600; |
185 | 725 | s++; |
186 | 725 | break; |
187 | 292 | case 'm': |
188 | 568 | case 'M': |
189 | 568 | tmp += (uint64_t)n * 60; |
190 | 568 | s++; |
191 | 568 | break; |
192 | 279 | case 's': |
193 | 601 | case 'S': |
194 | 601 | tmp += (uint64_t)n; |
195 | 601 | s++; |
196 | 601 | break; |
197 | 26.5k | case '\0': |
198 | | /* Plain number? */ |
199 | 26.5k | if (tmp != 0ULL) { |
200 | 93 | return DNS_R_SYNTAX; |
201 | 93 | } |
202 | 26.4k | tmp = n; |
203 | 26.4k | break; |
204 | 83 | default: |
205 | 83 | return DNS_R_SYNTAX; |
206 | 31.7k | } |
207 | 31.7k | } while (*s != '\0'); |
208 | | |
209 | 30.0k | if (tmp > 0xffffffffULL) { |
210 | 11 | return ISC_R_RANGE; |
211 | 11 | } |
212 | | |
213 | 30.0k | *ttl = (uint32_t)(tmp & 0xffffffffUL); |
214 | 30.0k | return ISC_R_SUCCESS; |
215 | 30.0k | } |