/* chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2002 * Copyright (C) Miroslav Lichvar 2014-2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ********************************************************************** ======================================================================= Routines to compute the expected length of a command or reply packet. These operate on the RAW NETWORK packets, from the point of view of integer endianness within the structures. */ #include "config.h" #include "sysincl.h" #include "util.h" #include "pktlength.h" #define PADDING_LENGTH_(request_length, reply_length) \ (uint16_t)((request_length) < (reply_length) ? (reply_length) - (request_length) : 0) #define PADDING_LENGTH(request_data, reply_data) \ PADDING_LENGTH_(offsetof(CMD_Request, request_data), offsetof(CMD_Reply, reply_data)) #define REQ_LENGTH_ENTRY(request_data_field, reply_data_field) \ { offsetof(CMD_Request, data.request_data_field.EOR), \ PADDING_LENGTH(data.request_data_field.EOR, data.reply_data_field.EOR) } #define RPY_LENGTH_ENTRY(reply_data_field) \ offsetof(CMD_Reply, data.reply_data_field.EOR) /* ================================================== */ struct request_length { uint16_t command; uint16_t padding; }; static const struct request_length request_lengths[] = { REQ_LENGTH_ENTRY(null, null), /* NULL */ REQ_LENGTH_ENTRY(online, null), /* ONLINE */ REQ_LENGTH_ENTRY(offline, null), /* OFFLINE */ REQ_LENGTH_ENTRY(burst, null), /* BURST */ REQ_LENGTH_ENTRY(modify_minpoll, null), /* MODIFY_MINPOLL */ REQ_LENGTH_ENTRY(modify_maxpoll, null), /* MODIFY_MAXPOLL */ REQ_LENGTH_ENTRY(dump, null), /* DUMP */ REQ_LENGTH_ENTRY(modify_maxdelay, null), /* MODIFY_MAXDELAY */ REQ_LENGTH_ENTRY(modify_maxdelayratio, null), /* MODIFY_MAXDELAYRATIO */ REQ_LENGTH_ENTRY(modify_maxupdateskew, null), /* MODIFY_MAXUPDATESKEW */ REQ_LENGTH_ENTRY(logon, null), /* LOGON */ REQ_LENGTH_ENTRY(settime, manual_timestamp), /* SETTIME */ { 0, 0 }, /* LOCAL */ REQ_LENGTH_ENTRY(manual, null), /* MANUAL */ REQ_LENGTH_ENTRY(null, n_sources), /* N_SOURCES */ REQ_LENGTH_ENTRY(source_data, source_data), /* SOURCE_DATA */ REQ_LENGTH_ENTRY(null, null), /* REKEY */ REQ_LENGTH_ENTRY(allow_deny, null), /* ALLOW */ REQ_LENGTH_ENTRY(allow_deny, null), /* ALLOWALL */ REQ_LENGTH_ENTRY(allow_deny, null), /* DENY */ REQ_LENGTH_ENTRY(allow_deny, null), /* DENYALL */ REQ_LENGTH_ENTRY(allow_deny, null), /* CMDALLOW */ REQ_LENGTH_ENTRY(allow_deny, null), /* CMDALLOWALL */ REQ_LENGTH_ENTRY(allow_deny, null), /* CMDDENY */ REQ_LENGTH_ENTRY(allow_deny, null), /* CMDDENYALL */ REQ_LENGTH_ENTRY(ac_check, null), /* ACCHECK */ REQ_LENGTH_ENTRY(ac_check, null), /* CMDACCHECK */ { 0, 0 }, /* ADD_SERVER */ { 0, 0 }, /* ADD_PEER */ REQ_LENGTH_ENTRY(del_source, null), /* DEL_SOURCE */ REQ_LENGTH_ENTRY(null, null), /* WRITERTC */ REQ_LENGTH_ENTRY(dfreq, null), /* DFREQ */ { 0, 0 }, /* DOFFSET - not supported */ REQ_LENGTH_ENTRY(null, tracking), /* TRACKING */ REQ_LENGTH_ENTRY(sourcestats, sourcestats), /* SOURCESTATS */ REQ_LENGTH_ENTRY(null, rtc), /* RTCREPORT */ REQ_LENGTH_ENTRY(null, null), /* TRIMRTC */ REQ_LENGTH_ENTRY(null, null), /* CYCLELOGS */ { 0, 0 }, /* SUBNETS_ACCESSED - not supported */ { 0, 0 }, /* CLIENT_ACCESSES - not supported */ { 0, 0 }, /* CLIENT_ACCESSES_BY_INDEX - not supported */ REQ_LENGTH_ENTRY(null, manual_list), /* MANUAL_LIST */ REQ_LENGTH_ENTRY(manual_delete, null), /* MANUAL_DELETE */ REQ_LENGTH_ENTRY(null, null), /* MAKESTEP */ REQ_LENGTH_ENTRY(null, activity), /* ACTIVITY */ REQ_LENGTH_ENTRY(modify_minstratum, null), /* MODIFY_MINSTRATUM */ REQ_LENGTH_ENTRY(modify_polltarget, null), /* MODIFY_POLLTARGET */ REQ_LENGTH_ENTRY(modify_maxdelaydevratio, null), /* MODIFY_MAXDELAYDEVRATIO */ REQ_LENGTH_ENTRY(null, null), /* RESELECT */ REQ_LENGTH_ENTRY(reselect_distance, null), /* RESELECTDISTANCE */ REQ_LENGTH_ENTRY(modify_makestep, null), /* MODIFY_MAKESTEP */ REQ_LENGTH_ENTRY(null, smoothing), /* SMOOTHING */ REQ_LENGTH_ENTRY(smoothtime, null), /* SMOOTHTIME */ REQ_LENGTH_ENTRY(null, null), /* REFRESH */ REQ_LENGTH_ENTRY(null, server_stats), /* SERVER_STATS */ { 0, 0 }, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */ { 0, 0 }, /* LOCAL2 - not supported */ REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */ { 0, 0 }, /* ADD_SERVER2 */ { 0, 0 }, /* ADD_PEER2 */ { 0, 0 }, /* ADD_SERVER3 */ { 0, 0 }, /* ADD_PEER3 */ REQ_LENGTH_ENTRY(null, null), /* SHUTDOWN */ REQ_LENGTH_ENTRY(null, null), /* ONOFFLINE */ REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SOURCE */ REQ_LENGTH_ENTRY(ntp_source_name, ntp_source_name), /* NTP_SOURCE_NAME */ REQ_LENGTH_ENTRY(null, null), /* RESET_SOURCES */ REQ_LENGTH_ENTRY(auth_data, auth_data), /* AUTH_DATA */ REQ_LENGTH_ENTRY(client_accesses_by_index, client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */ REQ_LENGTH_ENTRY(select_data, select_data), /* SELECT_DATA */ REQ_LENGTH_ENTRY(null, null), /* RELOAD_SOURCES */ REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET2 */ REQ_LENGTH_ENTRY(modify_select_opts, null), /* MODIFY_SELECTOPTS */ REQ_LENGTH_ENTRY(modify_offset, null), /* MODIFY_OFFSET */ REQ_LENGTH_ENTRY(local, null), /* LOCAL3 */ }; static const uint16_t reply_lengths[] = { 0, /* empty slot */ RPY_LENGTH_ENTRY(null), /* NULL */ RPY_LENGTH_ENTRY(n_sources), /* N_SOURCES */ RPY_LENGTH_ENTRY(source_data), /* SOURCE_DATA */ 0, /* MANUAL_TIMESTAMP */ RPY_LENGTH_ENTRY(tracking), /* TRACKING */ RPY_LENGTH_ENTRY(sourcestats), /* SOURCESTATS */ RPY_LENGTH_ENTRY(rtc), /* RTC */ 0, /* SUBNETS_ACCESSED - not supported */ 0, /* CLIENT_ACCESSES - not supported */ 0, /* CLIENT_ACCESSES_BY_INDEX - not supported */ 0, /* MANUAL_LIST - not supported */ RPY_LENGTH_ENTRY(activity), /* ACTIVITY */ RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */ 0, /* SERVER_STATS - not supported */ 0, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */ 0, /* NTP_DATA - not supported */ RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */ RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */ RPY_LENGTH_ENTRY(ntp_source_name), /* NTP_SOURCE_NAME */ RPY_LENGTH_ENTRY(auth_data), /* AUTH_DATA */ RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */ 0, /* SERVER_STATS2 - not supported */ RPY_LENGTH_ENTRY(select_data), /* SELECT_DATA */ 0, /* SERVER_STATS3 - not supported */ RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS4 */ RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA2 */ }; /* ================================================== */ int PKL_CommandLength(CMD_Request *r) { uint32_t type; int command_length; assert(sizeof (request_lengths) / sizeof (request_lengths[0]) == N_REQUEST_TYPES); type = ntohs(r->command); if (type >= N_REQUEST_TYPES) return 0; command_length = request_lengths[type].command; if (!command_length) return 0; return command_length + PKL_CommandPaddingLength(r); } /* ================================================== */ int PKL_CommandPaddingLength(CMD_Request *r) { uint32_t type; if (r->version < PROTO_VERSION_PADDING) return 0; type = ntohs(r->command); if (type >= N_REQUEST_TYPES) return 0; return request_lengths[ntohs(r->command)].padding; } /* ================================================== */ int PKL_ReplyLength(CMD_Reply *r) { uint32_t type; assert(sizeof (reply_lengths) / sizeof (reply_lengths[0]) == N_REPLY_TYPES); type = ntohs(r->reply); /* Note that reply type codes start from 1, not 0 */ if (type < 1 || type >= N_REPLY_TYPES) return 0; return reply_lengths[type]; } /* ================================================== */