]> git.ipfire.org Git - thirdparty/chrony.git/blame - ntp_ext.c
cmdmon: save NTS cookies and server keys on dump command
[thirdparty/chrony.git] / ntp_ext.c
CommitLineData
cabcccd6
ML
1/*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2019
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 **********************************************************************
21
22 =======================================================================
23
725beb36 24 Functions for adding and parsing NTPv4 extension fields
cabcccd6
ML
25 */
26
27#include "config.h"
28
29#include "sysincl.h"
30
31#include "ntp_ext.h"
32
33struct ExtFieldHeader {
34 uint16_t type;
35 uint16_t length;
36};
37
38/* ================================================== */
39
725beb36
ML
40static int
41format_field(unsigned char *buffer, int buffer_length, int start,
42 int type, int body_length, int *length, void **body)
43{
44 struct ExtFieldHeader *header;
45
46 if (buffer_length < 0 || start < 0 || buffer_length <= start ||
47 buffer_length - start < sizeof (*header) || start % 4 != 0)
48 return 0;
49
50 header = (struct ExtFieldHeader *)(buffer + start);
51
52 if (body_length < 0 || sizeof (*header) + body_length > 0xffff ||
53 start + sizeof (*header) + body_length > buffer_length || body_length % 4 != 0)
54 return 0;
55
56 header->type = htons(type);
57 header->length = htons(sizeof (*header) + body_length);
58 *length = sizeof (*header) + body_length;
59 *body = header + 1;
60
61 return 1;
62}
63
64/* ================================================== */
65
66int
67NEF_SetField(unsigned char *buffer, int buffer_length, int start,
68 int type, void *body, int body_length, int *length)
69{
70 void *ef_body;
71
72 if (!format_field(buffer, buffer_length, start, type, body_length, length, &ef_body))
73 return 0;
74
75 memcpy(ef_body, body, body_length);
76
77 return 1;
78}
79
80/* ================================================== */
81
82int
83NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type, int body_length, void **body)
84{
85 int ef_length, length = info->length;
86
87 if (length < NTP_HEADER_LENGTH || length >= sizeof (*packet) || length % 4 != 0)
88 return 0;
89
90 /* Only NTPv4 packets can have extension fields */
91 if (info->version != 4)
92 return 0;
93
94 if (!format_field((unsigned char *)packet, sizeof (*packet), length,
95 type, body_length, &ef_length, body))
96 return 0;
97
98 if (ef_length < NTP_MIN_EF_LENGTH)
99 return 0;
100
101 info->length += ef_length;
102 info->ext_fields++;
103
104 return 1;
105}
106
107/* ================================================== */
108
109int
110NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
111 int type, void *body, int body_length)
112{
113 void *ef_body;
114
115 if (!NEF_AddBlankField(packet, info, type, body_length, &ef_body))
116 return 0;
117
118 memcpy(ef_body, body, body_length);
119
120 return 1;
121}
122
123/* ================================================== */
124
cabcccd6
ML
125int
126NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
127 int *length, int *type, void **body, int *body_length)
128{
129 struct ExtFieldHeader *header;
130 int ef_length;
131
132 if (buffer_length < 0 || start < 0 || buffer_length <= start ||
133 buffer_length - start < sizeof (*header))
134 return 0;
135
136 header = (struct ExtFieldHeader *)(buffer + start);
137
138 assert(sizeof (*header) == 4);
139
140 ef_length = ntohs(header->length);
141
142 if (ef_length < (int)(sizeof (*header)) || start + ef_length > buffer_length ||
143 ef_length % 4 != 0)
144 return 0;
145
146 if (length)
147 *length = ef_length;
148 if (type)
149 *type = ntohs(header->type);
150 if (body)
151 *body = header + 1;
152 if (body_length)
153 *body_length = ef_length - sizeof (*header);
154
155 return 1;
156}
157
158/* ================================================== */
159
160int
161NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
162 int *length, int *type, void **body, int *body_length)
163{
164 int ef_length;
165
166 if (packet_length <= NTP_HEADER_LENGTH || packet_length > sizeof (*packet) ||
167 packet_length <= start || packet_length % 4 != 0 ||
168 start < NTP_HEADER_LENGTH || start % 4 != 0)
169 return 0;
170
171 /* Only NTPv4 packets have extension fields */
172 if (NTP_LVM_TO_VERSION(packet->lvm) != 4)
173 return 0;
174
175 /* Check if the remaining data is a MAC. RFC 7822 specifies the maximum
176 length of a MAC in NTPv4 packets in order to enable deterministic
177 parsing. */
178 if (packet_length - start <= NTP_MAX_V4_MAC_LENGTH)
179 return 0;
180
181 if (!NEF_ParseSingleField((unsigned char *)packet, packet_length, start,
182 &ef_length, type, body, body_length))
183 return 0;
184
185 if (ef_length < NTP_MIN_EF_LENGTH)
186 return 0;
187
188 if (length)
189 *length = ef_length;
190
191 return 1;
192}