diff options
Diffstat (limited to 'pktlength.c')
-rw-r--r-- | pktlength.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/pktlength.c b/pktlength.c new file mode 100644 index 0000000..2547689 --- /dev/null +++ b/pktlength.c @@ -0,0 +1,218 @@ +/* + 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 */ + REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET */ + 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 */ + REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */ + 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 */ +}; + +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 */ + RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */ + 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 */ + RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS2 */ + RPY_LENGTH_ENTRY(select_data), /* SELECT_DATA */ +}; + +/* ================================================== */ + +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]; +} + +/* ================================================== */ + |