• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "sntp_client.h"
17 #include "ntp_trusted_time.h"
18 
19 #include <netdb.h>
20 #include <securec.h>
21 #include <sstream>
22 #include <sys/time.h>
23 
24 #include "time_sysevent.h"
25 
26 namespace OHOS {
27 namespace MiscServices {
28 namespace {
29 constexpr uint64_t SECONDS_SINCE_FIRST_EPOCH = 2208988800; // Seconds from 1/1/1900 00.00 to 1/1/1970 00.00;
30 constexpr uint64_t MILLISECOND_TO_SECOND = 1000;
31 constexpr uint64_t FRACTION_TO_SECOND = 0x100000000;
32 constexpr uint64_t UINT32_MASK = 0xFFFFFFFF;
33 constexpr int VERSION_MASK = 0x38;
34 constexpr int MODE_MASK = 0x7;
35 constexpr int32_t INDEX_ZERO = 0;
36 constexpr int32_t INDEX_ONE = 1;
37 constexpr int32_t INDEX_TWO = 2;
38 constexpr int32_t INDEX_THREE = 3;
39 constexpr int32_t INDEX_FOUR = 4;
40 constexpr int32_t TIME_OUT = 5;
41 constexpr unsigned char MODE_THREE = 3;
42 constexpr unsigned char VERSION_THREE = 3;
43 constexpr double TEN_TO_MINUS_SIX_POWER = 1.0e-6;
44 constexpr const char* NTP_PORT = "123";
45 constexpr int32_t NTP_MSG_OFFSET_ROOT_DELAY = 4;
46 constexpr int32_t NTP_MSG_OFFSET_ROOT_DISPERSION = 8;
47 constexpr int32_t NTP_MSG_OFFSET_REFERENCE_IDENTIFIER = 12;
48 constexpr int32_t REFERENCE_TIMESTAMP_OFFSET = 16;
49 constexpr int32_t ORIGINATE_TIMESTAMP_OFFSET = 24;
50 constexpr int32_t RECEIVE_TIMESTAMP_OFFSET = 32;
51 constexpr int32_t TRANSMIT_TIMESTAMP_OFFSET = 40;
52 constexpr int32_t NTP_PACKAGE_SIZE = 48;
53 constexpr int32_t SNTP_MSG_OFFSET_SIX = 6;
54 constexpr int32_t SNTP_MSG_OFFSET_THREE = 3;
55 } // namespace
56 
RequestTime(const std::string & host)57 bool SNTPClient::RequestTime(const std::string &host)
58 {
59     int bufLen = NTP_PACKAGE_SIZE;
60     struct addrinfo hints = { 0 };
61     struct addrinfo *addrs;
62     hints.ai_family = AF_INET;
63     hints.ai_socktype = SOCK_DGRAM;
64     hints.ai_protocol = IPPROTO_UDP;
65     int error = getaddrinfo(host.c_str(), NTP_PORT, &hints, &addrs);
66     if (error != 0) {
67         TIME_HILOGE(TIME_MODULE_SERVICE, "getaddrinfo failed error %{public}d", error);
68         return false;
69     }
70 
71     // Create a socket for sending data
72     int sendSocket = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
73     if (sendSocket < 0) {
74         TIME_HILOGE(TIME_MODULE_SERVICE,
75                     "create socket failed: %{public}s family: %{public}d socktype: %{public}d protocol: %{public}d",
76                     strerror(errno), addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
77         return false;
78     }
79 
80     // Set send and recv function timeout
81     struct timeval timeout = { TIME_OUT, 0 };
82     setsockopt(sendSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));
83     setsockopt(sendSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));
84     if (connect(sendSocket, addrs->ai_addr, addrs->ai_addrlen) < 0) {
85         TIME_HILOGE(TIME_MODULE_SERVICE, "socket connect failed: %{public}s", strerror(errno));
86         close(sendSocket);
87         return false;
88     }
89 
90     // Create the NTP tx timestamp and fill the fields in the msg to be tx
91     char sendBuf[NTP_PACKAGE_SIZE] = { 0 };
92     CreateMessage(sendBuf);
93     if (send(sendSocket, sendBuf, bufLen, 0) < 0) {
94         TIME_HILOGE(TIME_MODULE_SERVICE, "Send socket message failed: %{public}s, Host: %{public}s",
95                     strerror(errno), host.c_str());
96         close(sendSocket);
97         return false;
98     }
99 
100     char bufferRx[NTP_PACKAGE_SIZE] = { 0 };
101     // Receive until the peer closes the connection
102     if (recv(sendSocket, bufferRx, NTP_PACKAGE_SIZE, 0) < 0) {
103         TIME_HILOGE(TIME_MODULE_SERVICE, "Receive socket message failed: %{public}s, Host: %{public}s",
104                     strerror(errno), host.c_str());
105         close(sendSocket);
106         return false;
107     }
108     close(sendSocket);
109     if (!ReceivedMessage(bufferRx)) {
110         TIME_HILOGE(TIME_MODULE_SERVICE, "ReceivedMessage failed: Host: %{public}s", host.c_str());
111         return false;
112     }
113     return true;
114 }
115 
SetClockOffset(int clockOffset)116 void SNTPClient::SetClockOffset(int clockOffset)
117 {
118     m_clockOffset = clockOffset;
119 }
120 
GetNtpTimestamp64(int offset,const char * buffer)121 uint64_t SNTPClient::GetNtpTimestamp64(int offset, const char *buffer)
122 {
123     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
124     const int _len = sizeof(uint64_t);
125     char valueRx[_len];
126     errno_t ret = memset_s(valueRx, sizeof(uint64_t), 0, sizeof(uint64_t));
127     if (ret != EOK) {
128         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", ret);
129         return false;
130     }
131     int numOfBit = sizeof(uint64_t) - 1;
132     for (int loop = offset; loop < offset + _len; loop++) {
133         valueRx[numOfBit] = buffer[loop];
134         numOfBit--;
135     }
136 
137     uint64_t milliseconds;
138     ret = memcpy_s(&milliseconds, sizeof(uint64_t), valueRx, sizeof(uint64_t));
139     if (ret != EOK) {
140         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", ret);
141         return false;
142     }
143     return le64toh(milliseconds);
144 }
145 
ConvertUnixToNtp(struct ntp_timestamp * ntpTs,struct timeval * unixTs)146 void SNTPClient::ConvertUnixToNtp(struct ntp_timestamp *ntpTs, struct timeval *unixTs)
147 {
148     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
149     // 0x83AA7E80; the seconds from Jan 1, 1900 to Jan 1, 1970
150     ntpTs->second = unixTs->tv_sec + SECONDS_SINCE_FIRST_EPOCH; // 0x83AA7E80;
151     ntpTs->fraction =
152         static_cast<uint64_t>((unixTs->tv_usec + 1) * (1LL << RECEIVE_TIMESTAMP_OFFSET) * TEN_TO_MINUS_SIX_POWER);
153     TIME_HILOGD(TIME_MODULE_SERVICE, "end");
154 }
155 
156 /*
157   *	/// SNTP Timestamp Format (as described in RFC 2030)
158   *                         1                   2                   3
159   *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
160   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161   *   |                           Seconds                             |
162   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163   *   |                  Seconds Fraction (0-padded)                  |
164   *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165   */
ConvertNtpToStamp(uint64_t _ntpTs)166 int64_t SNTPClient::ConvertNtpToStamp(uint64_t _ntpTs)
167 {
168     auto second = static_cast<uint32_t>((_ntpTs >> RECEIVE_TIMESTAMP_OFFSET) & UINT32_MASK);
169     auto fraction = static_cast<uint32_t>(_ntpTs & UINT32_MASK);
170     if (second == 0 && fraction == 0) {
171         return 0;
172     }
173     if (second < SECONDS_SINCE_FIRST_EPOCH) {
174         return 0;
175     }
176     // convert sntp timestamp to seconds
177     return ((second - SECONDS_SINCE_FIRST_EPOCH) * MILLISECOND_TO_SECOND) +
178            ((fraction * MILLISECOND_TO_SECOND) / FRACTION_TO_SECOND);
179 }
180 
CreateMessage(char * buffer)181 void SNTPClient::CreateMessage(char *buffer)
182 {
183     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
184     struct ntp_timestamp ntp{};
185     struct timeval unix;
186 
187     gettimeofday(&unix, nullptr);
188     // convert unix time to ntp time
189     ConvertUnixToNtp(&ntp, &unix);
190     uint64_t _ntpTs = ntp.second;
191     _ntpTs = (_ntpTs << RECEIVE_TIMESTAMP_OFFSET) | ntp.fraction;
192     errno_t ret = TimeUtils::GetBootTimeMs(m_originateTimestamp);
193     if (ret != E_TIME_OK) {
194         return;
195     }
196 
197     SNTPMessage _sntpMsg{};
198     // Important, if you don't set the version/mode, the server will ignore you.
199     _sntpMsg.clear();
200     _sntpMsg._leapIndicator = 0;
201     _sntpMsg._versionNumber = VERSION_THREE;
202     _sntpMsg._mode = MODE_THREE;
203     // optional (?)
204     _sntpMsg._originateTimestamp = _ntpTs;
205     char value[sizeof(uint64_t)];
206     ret = memcpy_s(value, sizeof(uint64_t), &_sntpMsg._originateTimestamp, sizeof(uint64_t));
207     if (ret != EOK) {
208         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", ret);
209         return;
210     }
211     int numOfBit = sizeof(uint64_t) - 1;
212     int offsetEnd = ORIGINATE_TIMESTAMP_OFFSET + sizeof(uint64_t);
213     for (int loop = ORIGINATE_TIMESTAMP_OFFSET; loop < offsetEnd; loop++) {
214         buffer[loop] = value[numOfBit];
215         numOfBit--;
216     }
217     // create the 1-byte info in one go... the result should be 27 :)
218     buffer[INDEX_ZERO] = (_sntpMsg._leapIndicator << SNTP_MSG_OFFSET_SIX) |
219                          (_sntpMsg._versionNumber << SNTP_MSG_OFFSET_THREE) | _sntpMsg._mode;
220     TIME_HILOGD(TIME_MODULE_SERVICE, "end");
221 }
222 
ReceivedMessage(char * buffer)223 bool SNTPClient::ReceivedMessage(char *buffer)
224 {
225     int64_t receiveBootTime = 0;
226     errno_t ret = TimeUtils::GetBootTimeMs(receiveBootTime);
227     if (ret != E_TIME_OK) {
228         return false;
229     }
230     SNTPMessage _sntpMsg;
231     _sntpMsg.clear();
232     _sntpMsg._leapIndicator = buffer[INDEX_ZERO] >> SNTP_MSG_OFFSET_SIX;
233     _sntpMsg._versionNumber = (buffer[INDEX_ZERO] & VERSION_MASK) >> SNTP_MSG_OFFSET_THREE;
234     _sntpMsg._mode = (buffer[INDEX_ZERO] & MODE_MASK);
235     _sntpMsg._stratum = buffer[INDEX_ONE];
236     _sntpMsg._pollInterval = buffer[INDEX_TWO];
237     _sntpMsg._precision = buffer[INDEX_THREE];
238     _sntpMsg._rootDelay = GetNtpField32(NTP_MSG_OFFSET_ROOT_DELAY, buffer);
239     _sntpMsg._rootDispersion = GetNtpField32(NTP_MSG_OFFSET_ROOT_DISPERSION, buffer);
240     int _refId[INDEX_FOUR];
241     GetReferenceId(NTP_MSG_OFFSET_REFERENCE_IDENTIFIER, buffer, _refId);
242     _sntpMsg._referenceIdentifier[INDEX_ZERO] = _refId[INDEX_ZERO];
243     _sntpMsg._referenceIdentifier[INDEX_ONE] = _refId[INDEX_ONE];
244     _sntpMsg._referenceIdentifier[INDEX_TWO] = _refId[INDEX_TWO];
245     _sntpMsg._referenceIdentifier[INDEX_THREE] = _refId[INDEX_THREE];
246     _sntpMsg._referenceTimestamp = GetNtpTimestamp64(REFERENCE_TIMESTAMP_OFFSET, buffer);
247     _sntpMsg._originateTimestamp = GetNtpTimestamp64(ORIGINATE_TIMESTAMP_OFFSET, buffer);
248     _sntpMsg._receiveTimestamp = GetNtpTimestamp64(RECEIVE_TIMESTAMP_OFFSET, buffer);
249     _sntpMsg._transmitTimestamp = GetNtpTimestamp64(TRANSMIT_TIMESTAMP_OFFSET, buffer);
250     int64_t _originClient = m_originateTimestamp;
251     int64_t _receiveServer = ConvertNtpToStamp(_sntpMsg._receiveTimestamp);
252     int64_t _transmitServer = ConvertNtpToStamp(_sntpMsg._transmitTimestamp);
253     if (_transmitServer == 0 || _receiveServer == 0) {
254         return false;
255     }
256     int64_t _receiveClient = receiveBootTime;
257     int64_t _clockOffset = (((_receiveServer - _originClient) + (_transmitServer - _receiveClient)) / INDEX_TWO);
258     int64_t _roundTripDelay = (_receiveClient - _originClient) - (_transmitServer - _receiveServer);
259     mRoundTripTime = _roundTripDelay;
260     mNtpTime = receiveBootTime + _clockOffset;
261     TimeUtils::GetBootTimeMs(mNtpTimeReference);
262     SetClockOffset(_clockOffset);
263     TIME_HILOGI(TIME_MODULE_SERVICE, "_originClient:%{public}s, _receiveServer:%{public}s, _transmitServer:%{public}s,"
264                 "_receiveClient:%{public}s", std::to_string(_originClient).c_str(),
265                 std::to_string(_receiveServer).c_str(), std::to_string(_transmitServer).c_str(),
266                 std::to_string(_receiveClient).c_str());
267     TimeBehaviorReport(ReportEventCode::NTP_REFRESH,
268         std::to_string(_originClient) + "|" + std::to_string(_receiveClient),
269         std::to_string(_transmitServer) + "|" + std::to_string(_receiveServer), mNtpTime);
270     return true;
271 }
272 
GetNtpField32(int offset,const char * buffer)273 unsigned int SNTPClient::GetNtpField32(int offset, const char *buffer)
274 {
275     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
276     const int _len = sizeof(int);
277     char valueRx[_len];
278     errno_t ret = memset_s(valueRx, _len, 0, _len);
279     if (ret != EOK) {
280         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", ret);
281         return false;
282     }
283     int numOfBit = sizeof(int) - 1;
284     for (int loop = offset; loop < offset + _len; loop++) {
285         valueRx[numOfBit] = buffer[loop];
286         numOfBit--;
287     }
288 
289     unsigned int milliseconds;
290     errno_t retValue = memcpy_s(&milliseconds, sizeof(int), valueRx, sizeof(int));
291     if (retValue != EOK) {
292         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", retValue);
293         return false;
294     }
295     TIME_HILOGD(TIME_MODULE_SERVICE, "end");
296     return milliseconds;
297 }
298 
GetReferenceId(int offset,char * buffer,int * _outArray)299 void SNTPClient::GetReferenceId(int offset, char *buffer, int *_outArray)
300 {
301     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
302     const int _len = sizeof(int);
303     int num = 0;
304     for (int loop = offset; loop < offset + _len; loop++) {
305         _outArray[num] = buffer[loop];
306         num++;
307     }
308     TIME_HILOGD(TIME_MODULE_SERVICE, "end");
309 }
310 
clear()311 void SNTPClient::SNTPMessage::clear()
312 {
313     TIME_HILOGD(TIME_MODULE_SERVICE, "start");
314     errno_t ret = memset_s(this, sizeof(*this), 0, sizeof(*this));
315     if (ret != EOK) {
316         TIME_HILOGE(TIME_MODULE_SERVICE, "memcpy_s failed, err = %{public}d", ret);
317     }
318 }
319 
320 // LCOV_EXCL_START
321 // The method has no input parameters, impossible to construct fuzz test.
getNtpTime()322 int64_t SNTPClient::getNtpTime()
323 {
324     return mNtpTime;
325 }
326 
getNtpTimeReference()327 int64_t SNTPClient::getNtpTimeReference()
328 {
329     return mNtpTimeReference;
330 }
331 
getRoundTripTime()332 int64_t SNTPClient::getRoundTripTime()
333 {
334     return mRoundTripTime;
335 }
336 // LCOV_EXCL_STOP
337 } // namespace MiscServices
338 } // namespace OHOS