/* chronyd/chronyc - Programs for keeping computer clocks accurate. ********************************************************************** * Copyright (C) Richard P. Curnow 1997-2002 * * 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" /* ================================================== */ static int command_unpadded_length(CMD_Request *r) { int type; type = ntohs(r->command); if (type < 0 || type >= N_REQUEST_TYPES) { return 0; } else { switch (type) { case REQ_NULL: return offsetof(CMD_Request, data.null.EOR); case REQ_ONLINE: return offsetof(CMD_Request, data.online.EOR); case REQ_OFFLINE: return offsetof(CMD_Request, data.offline.EOR); case REQ_BURST: return offsetof(CMD_Request, data.burst.EOR); case REQ_MODIFY_MINPOLL: return offsetof(CMD_Request, data.modify_minpoll.EOR); case REQ_MODIFY_MAXPOLL: return offsetof(CMD_Request, data.modify_maxpoll.EOR); case REQ_DUMP: return offsetof(CMD_Request, data.dump.EOR); case REQ_MODIFY_MAXDELAY: return offsetof(CMD_Request, data.modify_maxdelay.EOR); case REQ_MODIFY_MAXDELAYRATIO: return offsetof(CMD_Request, data.modify_maxdelayratio.EOR); case REQ_MODIFY_MAXDELAYDEVRATIO: return offsetof(CMD_Request, data.modify_maxdelaydevratio.EOR); case REQ_MODIFY_MAXUPDATESKEW: return offsetof(CMD_Request, data.modify_maxupdateskew.EOR); case REQ_MODIFY_MAKESTEP: return offsetof(CMD_Request, data.modify_makestep.EOR); case REQ_LOGON : return offsetof(CMD_Request, data.logon.EOR); case REQ_SETTIME : return offsetof(CMD_Request, data.settime.EOR); case REQ_LOCAL : return offsetof(CMD_Request, data.local.EOR); case REQ_MANUAL : return offsetof(CMD_Request, data.manual.EOR); case REQ_N_SOURCES : return offsetof(CMD_Request, data.null.EOR); case REQ_SOURCE_DATA : return offsetof(CMD_Request, data.source_data.EOR); case REQ_REKEY : return offsetof(CMD_Request, data.null.EOR); case REQ_ALLOW : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_ALLOWALL : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_DENY : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_DENYALL : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_CMDALLOW : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_CMDALLOWALL : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_CMDDENY : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_CMDDENYALL : return offsetof(CMD_Request, data.allow_deny.EOR); case REQ_ACCHECK : return offsetof(CMD_Request, data.ac_check.EOR); case REQ_CMDACCHECK : return offsetof(CMD_Request, data.ac_check.EOR); case REQ_ADD_SERVER : return offsetof(CMD_Request, data.ntp_source.EOR); case REQ_ADD_PEER : return offsetof(CMD_Request, data.ntp_source.EOR); case REQ_DEL_SOURCE : return offsetof(CMD_Request, data.del_source.EOR); case REQ_WRITERTC : return offsetof(CMD_Request, data.null.EOR); case REQ_DFREQ : return offsetof(CMD_Request, data.dfreq.EOR); case REQ_DOFFSET : return offsetof(CMD_Request, data.doffset.EOR); case REQ_TRACKING : return offsetof(CMD_Request, data.null.EOR); case REQ_SOURCESTATS : return offsetof(CMD_Request, data.sourcestats.EOR); case REQ_RTCREPORT : return offsetof(CMD_Request, data.null.EOR); case REQ_TRIMRTC : return offsetof(CMD_Request, data.null.EOR); case REQ_CYCLELOGS : return offsetof(CMD_Request, data.null.EOR); case REQ_SUBNETS_ACCESSED : case REQ_CLIENT_ACCESSES: /* No longer supported */ return 0; case REQ_CLIENT_ACCESSES_BY_INDEX: return offsetof(CMD_Request, data.client_accesses_by_index.EOR); case REQ_MANUAL_LIST: return offsetof(CMD_Request, data.null.EOR); case REQ_MANUAL_DELETE: return offsetof(CMD_Request, data.manual_delete.EOR); case REQ_MAKESTEP: return offsetof(CMD_Request, data.null.EOR); case REQ_ACTIVITY: return offsetof(CMD_Request, data.null.EOR); case REQ_RESELECT: return offsetof(CMD_Request, data.null.EOR); case REQ_RESELECTDISTANCE: return offsetof(CMD_Request, data.reselect_distance.EOR); case REQ_MODIFY_MINSTRATUM: return offsetof(CMD_Request, data.modify_minstratum.EOR); case REQ_MODIFY_POLLTARGET: return offsetof(CMD_Request, data.modify_polltarget.EOR); case REQ_SMOOTHING: return offsetof(CMD_Request, data.null.EOR); case REQ_SMOOTHTIME: return offsetof(CMD_Request, data.smoothtime.EOR); default: /* If we fall through the switch, it most likely means we've forgotten to implement a new case */ assert(0); } } /* Catch-all case */ return 0; } /* ================================================== */ int PKL_CommandLength(CMD_Request *r) { int command_length; command_length = command_unpadded_length(r); if (!command_length) return 0; return command_length + PKL_CommandPaddingLength(r); } /* ================================================== */ #define PADDING_LENGTH_(request_length, reply_length) \ ((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)) int PKL_CommandPaddingLength(CMD_Request *r) { int type; if (r->version < PROTO_VERSION_PADDING) return 0; type = ntohs(r->command); if (type < 0 || type >= N_REQUEST_TYPES) return 0; switch (type) { case REQ_NULL: return PADDING_LENGTH(data, data.null.EOR); case REQ_ONLINE: return PADDING_LENGTH(data.online.EOR, data.null.EOR); case REQ_OFFLINE: return PADDING_LENGTH(data.offline.EOR, data.null.EOR); case REQ_BURST: return PADDING_LENGTH(data.burst.EOR, data.null.EOR); case REQ_MODIFY_MINPOLL: return PADDING_LENGTH(data.modify_minpoll.EOR, data.null.EOR); case REQ_MODIFY_MAXPOLL: return PADDING_LENGTH(data.modify_maxpoll.EOR, data.null.EOR); case REQ_DUMP: return PADDING_LENGTH(data.dump.EOR, data.null.EOR); case REQ_MODIFY_MAXDELAY: return PADDING_LENGTH(data.modify_maxdelay.EOR, data.null.EOR); case REQ_MODIFY_MAXDELAYRATIO: return PADDING_LENGTH(data.modify_maxdelayratio.EOR, data.null.EOR); case REQ_MODIFY_MAXDELAYDEVRATIO: return PADDING_LENGTH(data.modify_maxdelaydevratio.EOR, data.null.EOR); case REQ_MODIFY_MAXUPDATESKEW: return PADDING_LENGTH(data.modify_maxupdateskew.EOR, data.null.EOR); case REQ_MODIFY_MAKESTEP: return PADDING_LENGTH(data.modify_makestep.EOR, data.null.EOR); case REQ_LOGON: return PADDING_LENGTH(data.logon.EOR, data.null.EOR); case REQ_SETTIME: return PADDING_LENGTH(data.settime.EOR, data.manual_timestamp.EOR); case REQ_LOCAL: return PADDING_LENGTH(data.local.EOR, data.null.EOR); case REQ_MANUAL: return PADDING_LENGTH(data.manual.EOR, data.null.EOR); case REQ_N_SOURCES: return PADDING_LENGTH(data.null.EOR, data.n_sources.EOR); case REQ_SOURCE_DATA: return PADDING_LENGTH(data.source_data.EOR, data.source_data.EOR); case REQ_REKEY: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_ALLOW: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_ALLOWALL: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_DENY: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_DENYALL: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_CMDALLOW: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_CMDALLOWALL: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_CMDDENY: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_CMDDENYALL: return PADDING_LENGTH(data.allow_deny.EOR, data.null.EOR); case REQ_ACCHECK: return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR); case REQ_CMDACCHECK: return PADDING_LENGTH(data.ac_check.EOR, data.null.EOR); case REQ_ADD_SERVER: return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR); case REQ_ADD_PEER: return PADDING_LENGTH(data.ntp_source.EOR, data.null.EOR); case REQ_DEL_SOURCE: return PADDING_LENGTH(data.del_source.EOR, data.null.EOR); case REQ_WRITERTC: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_DFREQ: return PADDING_LENGTH(data.dfreq.EOR, data.null.EOR); case REQ_DOFFSET: return PADDING_LENGTH(data.doffset.EOR, data.null.EOR); case REQ_TRACKING: return PADDING_LENGTH(data.null.EOR, data.tracking.EOR); case REQ_SOURCESTATS: return PADDING_LENGTH(data.sourcestats.EOR, data.sourcestats.EOR); case REQ_RTCREPORT: return PADDING_LENGTH(data.null.EOR, data.rtc.EOR); case REQ_TRIMRTC: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_CYCLELOGS: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_SUBNETS_ACCESSED: case REQ_CLIENT_ACCESSES: /* No longer supported */ return 0; case REQ_CLIENT_ACCESSES_BY_INDEX: return PADDING_LENGTH(data.client_accesses_by_index.EOR, data.client_accesses_by_index.EOR); case REQ_MANUAL_LIST: return PADDING_LENGTH(data.null.EOR, data.manual_list.EOR); case REQ_MANUAL_DELETE: return PADDING_LENGTH(data.manual_delete.EOR, data.null.EOR); case REQ_MAKESTEP: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_ACTIVITY: return PADDING_LENGTH(data.null.EOR, data.activity.EOR); case REQ_RESELECT: return PADDING_LENGTH(data.null.EOR, data.null.EOR); case REQ_RESELECTDISTANCE: return PADDING_LENGTH(data.reselect_distance.EOR, data.null.EOR); case REQ_MODIFY_MINSTRATUM: return PADDING_LENGTH(data.modify_minstratum.EOR, data.null.EOR); case REQ_MODIFY_POLLTARGET: return PADDING_LENGTH(data.modify_polltarget.EOR, data.null.EOR); case REQ_SMOOTHING: return PADDING_LENGTH(data.null.EOR, data.smoothing.EOR); case REQ_SMOOTHTIME: return PADDING_LENGTH(data.smoothtime.EOR, data.null.EOR); default: /* If we fall through the switch, it most likely means we've forgotten to implement a new case */ assert(0); return 0; } } /* ================================================== */ int PKL_ReplyLength(CMD_Reply *r) { int type; type = ntohs(r->reply); /* Note that reply type codes start from 1, not 0 */ if (type < 1 || type >= N_REPLY_TYPES) { return 0; } else { switch (type) { case RPY_NULL: return offsetof(CMD_Reply, data.null.EOR); case RPY_N_SOURCES: return offsetof(CMD_Reply, data.n_sources.EOR); case RPY_SOURCE_DATA: return offsetof(CMD_Reply, data.source_data.EOR); case RPY_MANUAL_TIMESTAMP: return offsetof(CMD_Reply, data.manual_timestamp.EOR); case RPY_TRACKING: return offsetof(CMD_Reply, data.tracking.EOR); case RPY_SOURCESTATS: return offsetof(CMD_Reply, data.sourcestats.EOR); case RPY_RTC: return offsetof(CMD_Reply, data.rtc.EOR); case RPY_SUBNETS_ACCESSED : case RPY_CLIENT_ACCESSES: /* No longer supported */ return 0; case RPY_CLIENT_ACCESSES_BY_INDEX: { unsigned long nc = ntohl(r->data.client_accesses_by_index.n_clients); if (r->status == htons(STT_SUCCESS)) { if (nc > MAX_CLIENT_ACCESSES) return 0; return (offsetof(CMD_Reply, data.client_accesses_by_index.clients) + nc * sizeof(RPY_ClientAccesses_Client)); } else { return offsetof(CMD_Reply, data); } } case RPY_MANUAL_LIST: { unsigned long ns = ntohl(r->data.manual_list.n_samples); if (ns > MAX_MANUAL_LIST_SAMPLES) return 0; if (r->status == htons(STT_SUCCESS)) { return (offsetof(CMD_Reply, data.manual_list.samples) + ns * sizeof(RPY_ManualListSample)); } else { return offsetof(CMD_Reply, data); } } case RPY_ACTIVITY: return offsetof(CMD_Reply, data.activity.EOR); case RPY_SMOOTHING: return offsetof(CMD_Reply, data.smoothing.EOR); default: assert(0); } } return 0; } /* ================================================== */