Coverage Report

Created: 2026-09-03 06:30

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