Coverage Report

Created: 2025-08-03 06:33

/src/bind9/lib/dns/time.c
Line
Count
Source (jump to first uncovered line)
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
23.1k
dns_time64_totext(int64_t t, isc_buffer_t *target) {
34
23.1k
  struct tm tm;
35
23.1k
  char buf[sizeof("!!!!!!YYYY!!!!!!!!MM!!!!!!!!DD!!!!!!!!HH!!!!!!!!MM!!!!"
36
23.1k
      "!!!!SS")];
37
23.1k
  int secs;
38
23.1k
  unsigned int l;
39
23.1k
  isc_region_t region;
40
41
/*
42
 * Warning. Do NOT use arguments with side effects with these macros.
43
 */
44
1.28M
#define is_leap(y)   ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
45
513k
#define year_secs(y)   ((is_leap(y) ? 366 : 365) * 86400)
46
126k
#define month_secs(m, y) ((days[m] + ((m == 1 && is_leap(y)) ? 1 : 0)) * 86400)
47
48
23.1k
  tm.tm_year = 70;
49
31.0k
  while (t < 0) {
50
7.82k
    if (tm.tm_year == 0) {
51
0
      return ISC_R_RANGE;
52
0
    }
53
7.82k
    tm.tm_year--;
54
7.82k
    secs = year_secs(tm.tm_year + 1900);
55
7.82k
    t += secs;
56
7.82k
  }
57
505k
  while ((secs = year_secs(tm.tm_year + 1900)) <= t) {
58
482k
    t -= secs;
59
482k
    tm.tm_year++;
60
482k
    if (tm.tm_year + 1900 > 9999) {
61
0
      return ISC_R_RANGE;
62
0
    }
63
482k
  }
64
23.1k
  tm.tm_mon = 0;
65
126k
  while ((secs = month_secs(tm.tm_mon, tm.tm_year + 1900)) <= t) {
66
103k
    t -= secs;
67
103k
    tm.tm_mon++;
68
103k
  }
69
23.1k
  tm.tm_mday = 1;
70
304k
  while (86400 <= t) {
71
281k
    t -= 86400;
72
281k
    tm.tm_mday++;
73
281k
  }
74
23.1k
  tm.tm_hour = 0;
75
276k
  while (3600 <= t) {
76
253k
    t -= 3600;
77
253k
    tm.tm_hour++;
78
253k
  }
79
23.1k
  tm.tm_min = 0;
80
597k
  while (60 <= t) {
81
574k
    t -= 60;
82
574k
    tm.tm_min++;
83
574k
  }
84
23.1k
  tm.tm_sec = (int)t;
85
  /* yyyy  mm  dd  HH  MM  SS */
86
23.1k
  snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02d",
87
23.1k
     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
88
23.1k
     tm.tm_min, tm.tm_sec);
89
90
23.1k
  isc_buffer_availableregion(target, &region);
91
23.1k
  l = strlen(buf);
92
93
23.1k
  if (l > region.length) {
94
0
    return ISC_R_NOSPACE;
95
0
  }
96
97
23.1k
  memmove(region.base, buf, l);
98
23.1k
  isc_buffer_add(target, l);
99
23.1k
  return ISC_R_SUCCESS;
100
23.1k
}
101
102
int64_t
103
23.1k
dns_time64_from32(uint32_t value) {
104
23.1k
  isc_stdtime_t now = isc_stdtime_now();
105
23.1k
  int64_t start;
106
23.1k
  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
23.1k
  start = (int64_t)now;
116
23.1k
  if (isc_serial_gt(value, now)) {
117
3.02k
    t = start + (value - now);
118
20.1k
  } else {
119
20.1k
    t = start - (now - value);
120
20.1k
  }
121
122
23.1k
  return t;
123
23.1k
}
124
125
isc_result_t
126
23.1k
dns_time32_totext(uint32_t value, isc_buffer_t *target) {
127
23.1k
  return dns_time64_totext(dns_time64_from32(value), target);
128
23.1k
}
129
130
isc_result_t
131
3.69k
dns_time64_fromtext(const char *source, int64_t *target) {
132
3.69k
  int year, month, day, hour, minute, second;
133
3.69k
  int64_t value;
134
3.69k
  int secs;
135
3.69k
  int i;
136
137
3.69k
#define RANGE(min, max, value)                      \
138
21.5k
  do {                                        \
139
21.5k
    if (value < (min) || value > (max)) \
140
21.5k
      return ((ISC_R_RANGE));     \
141
21.5k
  } while (0)
142
143
3.69k
  if (strlen(source) != 14U) {
144
77
    return DNS_R_SYNTAX;
145
77
  }
146
  /*
147
   * Confirm the source only consists digits.  sscanf() allows some
148
   * minor exceptions.
149
   */
150
54.2k
  for (i = 0; i < 14; i++) {
151
50.5k
    if (!isdigit((unsigned char)source[i])) {
152
9
      return DNS_R_SYNTAX;
153
9
    }
154
50.5k
  }
155
3.61k
  if (sscanf(source, "%4d%2d%2d%2d%2d%2d", &year, &month, &day, &hour,
156
3.61k
       &minute, &second) != 6)
157
0
  {
158
0
    return DNS_R_SYNTAX;
159
0
  }
160
161
3.61k
  RANGE(0, 9999, year);
162
3.61k
  RANGE(1, 12, month);
163
3.59k
  RANGE(1, days[month - 1] + ((month == 2 && is_leap(year)) ? 1 : 0),
164
3.59k
        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.58k
  RANGE(0, 23, hour);
174
3.57k
  RANGE(0, 59, minute);
175
3.57k
  RANGE(0, 60, second); /* 60 == leap second. */
176
177
  /*
178
   * Calculate seconds from epoch.
179
   * Note: this uses a idealized calendar.
180
   */
181
3.56k
  value = second + (60 * minute) + (3600 * hour) + ((day - 1) * 86400);
182
16.6k
  for (i = 0; i < (month - 1); i++) {
183
13.1k
    value += days[i] * 86400;
184
13.1k
  }
185
3.56k
  if (is_leap(year) && month > 2) {
186
701
    value += 86400;
187
701
  }
188
3.56k
  if (year < 1970) {
189
126k
    for (i = 1969; i >= year; i--) {
190
126k
      secs = (is_leap(i) ? 366 : 365) * 86400;
191
126k
      value -= secs;
192
126k
    }
193
3.20k
  } else {
194
620k
    for (i = 1970; i < year; i++) {
195
617k
      secs = (is_leap(i) ? 366 : 365) * 86400;
196
617k
      value += secs;
197
617k
    }
198
3.20k
  }
199
200
3.56k
  *target = value;
201
3.56k
  return ISC_R_SUCCESS;
202
3.57k
}
203
204
isc_result_t
205
1.14k
dns_time32_fromtext(const char *source, uint32_t *target) {
206
1.14k
  int64_t value64;
207
1.14k
  isc_result_t result;
208
1.14k
  result = dns_time64_fromtext(source, &value64);
209
1.14k
  if (result != ISC_R_SUCCESS) {
210
90
    return result;
211
90
  }
212
1.05k
  *target = (uint32_t)value64;
213
214
1.05k
  return ISC_R_SUCCESS;
215
1.14k
}