Coverage Report

Created: 2026-09-01 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/time.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 <inttypes.h>
18
#include <stdio.h>
19
#include <time.h>
20
21
#include <isc/region.h>
22
#include <isc/result.h>
23
#include <isc/serial.h>
24
#include <isc/stdtime.h>
25
#include <isc/string.h>
26
#include <isc/util.h>
27
28
#include <dns/time.h>
29
30
static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
31
32
isc_result_t
33
15.6k
dns_time64_totext(int64_t t, isc_buffer_t *target) {
34
15.6k
  struct tm tm;
35
15.6k
  char buf[sizeof("!!!!!!YYYY!!!!!!!!MM!!!!!!!!DD!!!!!!!!HH!!!!!!!!MM!!!!"
36
15.6k
      "!!!!SS")];
37
15.6k
  int secs;
38
15.6k
  unsigned int l;
39
15.6k
  isc_region_t region;
40
41
/*
42
 * Warning. Do NOT use arguments with side effects with these macros.
43
 */
44
2.53M
#define is_leap(y)   ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
45
372k
#define year_secs(y) ((is_leap(y) ? 366 : 365) * 86400)
46
87.9k
#define month_secs(m, y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0)) * 86400)
47
48
15.6k
  tm.tm_year = 70;
49
22.7k
  while (t < 0) {
50
7.13k
    if (tm.tm_year == 0) {
51
0
      return ISC_R_RANGE;
52
0
    }
53
7.13k
    tm.tm_year--;
54
7.13k
    secs = year_secs(tm.tm_year + 1900);
55
7.13k
    t += secs;
56
7.13k
  }
57
365k
  while ((secs = year_secs(tm.tm_year + 1900)) <= t) {
58
349k
    t -= secs;
59
349k
    tm.tm_year++;
60
349k
    if (tm.tm_year + 1900 > 9999) {
61
0
      return ISC_R_RANGE;
62
0
    }
63
349k
  }
64
15.6k
  tm.tm_mon = 0;
65
87.9k
  while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) {
66
72.3k
    t -= secs;
67
72.3k
    tm.tm_mon++;
68
72.3k
  }
69
15.6k
  tm.tm_mday = 1;
70
223k
  while (86400 <= t) {
71
208k
    t -= 86400;
72
208k
    tm.tm_mday++;
73
208k
  }
74
15.6k
  tm.tm_hour = 0;
75
188k
  while (3600 <= t) {
76
173k
    t -= 3600;
77
173k
    tm.tm_hour++;
78
173k
  }
79
15.6k
  tm.tm_min = 0;
80
434k
  while (60 <= t) {
81
418k
    t -= 60;
82
418k
    tm.tm_min++;
83
418k
  }
84
15.6k
  tm.tm_sec = (int)t;
85
  /* yyyy  mm  dd  HH  MM  SS */
86
15.6k
  snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d",
87
15.6k
     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
88
15.6k
     tm.tm_min, tm.tm_sec);
89
90
15.6k
  isc_buffer_availableregion(target, &region);
91
15.6k
  l = strlen(buf);
92
93
15.6k
  if (l > region.length) {
94
0
    return ISC_R_NOSPACE;
95
0
  }
96
97
15.6k
  memmove(region.base, buf, l);
98
15.6k
  isc_buffer_add(target, l);
99
15.6k
  return ISC_R_SUCCESS;
100
15.6k
}
101
102
int64_t
103
15.6k
dns_time64_from32(uint32_t value) {
104
15.6k
  isc_stdtime_t now = isc_stdtime_now();
105
15.6k
  int64_t start;
106
15.6k
  int64_t t;
107
108
  /*
109
   * Adjust the time to the closest epoch.  This should be changed
110
   * to use a 64-bit counterpart to isc_stdtime_now() if one ever
111
   * is defined, but even the current code is good until the year
112
   * 2106.
113
   */
114
115
15.6k
  start = (int64_t)now;
116
15.6k
  if (isc_serial_gt(value, now)) {
117
2.24k
    t = start + (value - now);
118
13.3k
  } else {
119
13.3k
    t = start - (now - value);
120
13.3k
  }
121
122
15.6k
  return t;
123
15.6k
}
124
125
isc_result_t
126
15.6k
dns_time32_totext(uint32_t value, isc_buffer_t *target) {
127
15.6k
  return dns_time64_totext(dns_time64_from32(value), target);
128
15.6k
}
129
130
isc_result_t
131
3.59k
dns_time64_fromtext(const char *source, int64_t *target) {
132
3.59k
  int year, month, day, hour, minute, second;
133
3.59k
  int64_t value;
134
3.59k
  int secs;
135
3.59k
  int i;
136
137
3.59k
#define RANGE(min, max, value)                      \
138
21.0k
  do {                                        \
139
21.0k
    if (value < (min) || value > (max)) \
140
21.0k
      return ((ISC_R_RANGE));     \
141
21.0k
  } while (0)
142
143
3.59k
  if (strlen(source) != 14U) {
144
64
    return DNS_R_SYNTAX;
145
64
  }
146
  /*
147
   * Confirm the source only consists digits.  sscanf() allows some
148
   * minor exceptions.
149
   */
150
52.8k
  for (i = 0; i < 14; i++) {
151
49.3k
    if (!isdigit((unsigned char)source[i])) {
152
11
      return DNS_R_SYNTAX;
153
11
    }
154
49.3k
  }
155
3.52k
  if (sscanf(source, "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour,
156
3.52k
       &minute, &second) != 6)
157
0
  {
158
0
    return DNS_R_SYNTAX;
159
0
  }
160
161
3.52k
  RANGE(0, 9999, year);
162
3.52k
  RANGE(1, 12, month);
163
3.51k
  RANGE(1, days[month - 1] + ((month == 2 && is_leap(year)) ? 1 : 0),
164
3.51k
        day);
165
#ifdef __COVERITY__
166
  /*
167
   * Use a simplified range to silence Coverity warning (in
168
   * arithmetic with day below).
169
   */
170
  RANGE(1, 31, day);
171
#endif /* __COVERITY__ */
172
173
3.50k
  RANGE(0, 23, hour);
174
3.49k
  RANGE(0, 59, minute);
175
3.49k
  RANGE(0, 60, second); /* 60 == leap second. */
176
177
  /*
178
   * Calculate seconds from epoch.
179
   * Note: this uses a idealized calendar.
180
   */
181
3.49k
  value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400);
182
16.8k
  for (i = 0; i < (month - 1); i++) {
183
13.3k
    value += days[i] * 86400;
184
13.3k
  }
185
3.49k
  if (is_leap(year) && month > 2) {
186
575
    value += 86400;
187
575
  }
188
3.49k
  if (year < 1970) {
189
118k
    for (i = 1969; i >= year; i--) {
190
117k
      secs = (is_leap(i) ? 366 : 365) * 86400;
191
117k
      value -= secs;
192
117k
    }
193
3.09k
  } else {
194
2.03M
    for (i = 1970; i < year; i++) {
195
2.02M
      secs = (is_leap(i) ? 366 : 365) * 86400;
196
2.02M
      value += secs;
197
2.02M
    }
198
3.09k
  }
199
200
3.49k
  *target = value;
201
3.49k
  return ISC_R_SUCCESS;
202
3.49k
}
203
204
isc_result_t
205
1.49k
dns_time32_fromtext(const char *source, uint32_t *target) {
206
1.49k
  int64_t value64;
207
208
1.49k
  RETERR(dns_time64_fromtext(source, &value64));
209
1.42k
  *target = (uint32_t)value64;
210
211
1.42k
  return ISC_R_SUCCESS;
212
1.49k
}