typedef struct {
uint32_t first_index;
uint32_t n_clients;
+ uint32_t min_hits;
uint32_t reset;
int32_t EOR;
} REQ_ClientAccessesByIndex;
"\0(e.g. Sep 25, 2015 16:30:05 or 16:30:05)\0"
"\0\0NTP access:\0\0"
"accheck <address>\0Check whether address is allowed\0"
- "clients [-r]\0Report on clients that have accessed the server\0"
+ "clients [-p <packets>] [-r]\0Report on clients that accessed the server\0"
"serverstats\0Display statistics of the server\0"
"allow [<subnet>]\0Allow access to subnet as a default\0"
"allow all [<subnet>]\0Allow access to subnet and all children\0"
CMD_Request request;
CMD_Reply reply;
IPAddr ip;
- uint32_t i, n_clients, next_index, n_indices, reset;
+ uint32_t i, n_clients, next_index, n_indices, min_hits, reset;
RPY_ClientAccesses_Client *client;
- char name[50], *opt;
+ char name[50], *opt, *arg;
next_index = 0;
+ min_hits = 0;
reset = 0;
while (*line) {
opt = line;
line = CPS_SplitWord(line);
- if (strcmp(opt, "-r") == 0)
+ if (strcmp(opt, "-p") == 0) {
+ arg = line;
+ line = CPS_SplitWord(line);
+ if (sscanf(arg, "%"SCNu32, &min_hits) != 1) {
+ LOG(LOGS_ERR, "Invalid syntax for clients command");
+ return 0;
+ }
+ } else if (strcmp(opt, "-r") == 0) {
reset = 1;
+ }
}
print_header("Hostname NTP Drop Int IntL Last Cmd Drop Int Last");
request.command = htons(REQ_CLIENT_ACCESSES_BY_INDEX3);
request.data.client_accesses_by_index.first_index = htonl(next_index);
request.data.client_accesses_by_index.n_clients = htonl(MAX_CLIENT_ACCESSES);
+ request.data.client_accesses_by_index.min_hits = htonl(min_hits);
request.data.client_accesses_by_index.reset = htonl(reset);
if (!request_reply(&request, &reply, RPY_CLIENT_ACCESSES_BY_INDEX2, 0))
/* ================================================== */
int
-CLG_GetClientAccessReportByIndex(int index, int reset,
+CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
RPT_ClientAccessByIndex_Report *report, struct timespec *now)
{
Record *record;
uint32_t now_ts;
+ int r;
if (!active || index < 0 || index >= ARR_GetSize(records))
return 0;
if (record->ip_addr.family == IPADDR_UNSPEC)
return 0;
- now_ts = get_ts_from_timespec(now);
-
- report->ip_addr = record->ip_addr;
- report->ntp_hits = record->ntp_hits;
- report->cmd_hits = record->cmd_hits;
- report->ntp_drops = record->ntp_drops;
- report->cmd_drops = record->cmd_drops;
- report->ntp_interval = get_interval(record->ntp_rate);
- report->cmd_interval = get_interval(record->cmd_rate);
- report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
- report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_ntp_hit);
- report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_cmd_hit);
+ r = min_hits == 0 ||
+ record->ntp_hits >= min_hits || record->cmd_hits >= min_hits;
+
+ if (r) {
+ now_ts = get_ts_from_timespec(now);
+
+ report->ip_addr = record->ip_addr;
+ report->ntp_hits = record->ntp_hits;
+ report->cmd_hits = record->cmd_hits;
+ report->ntp_drops = record->ntp_drops;
+ report->cmd_drops = record->cmd_drops;
+ report->ntp_interval = get_interval(record->ntp_rate);
+ report->cmd_interval = get_interval(record->cmd_rate);
+ report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
+ report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_ntp_hit);
+ report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_cmd_hit);
+ }
if (reset) {
record->ntp_hits = record->cmd_hits = 0;
record->ntp_drops = record->cmd_drops = 0;
}
- return 1;
+ return r;
}
/* ================================================== */
/* And some reporting functions, for use by chronyc. */
extern int CLG_GetNumberOfIndices(void);
-extern int CLG_GetClientAccessReportByIndex(int index, int reset,
+extern int CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
RPT_ClientAccessByIndex_Report *report,
struct timespec *now);
extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
RPT_ClientAccessByIndex_Report report;
RPY_ClientAccesses_Client *client;
int n_indices;
- uint32_t i, j, req_first_index, req_n_clients, req_reset;
+ uint32_t i, j, req_first_index, req_n_clients, req_min_hits, req_reset;
struct timespec now;
SCH_GetLastEventTime(&now, NULL, NULL);
req_n_clients = ntohl(rx_message->data.client_accesses_by_index.n_clients);
if (req_n_clients > MAX_CLIENT_ACCESSES)
req_n_clients = MAX_CLIENT_ACCESSES;
+ req_min_hits = ntohl(rx_message->data.client_accesses_by_index.min_hits);
req_reset = ntohl(rx_message->data.client_accesses_by_index.reset);
n_indices = CLG_GetNumberOfIndices();
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
- if (!CLG_GetClientAccessReportByIndex(i, req_reset, &report, &now))
+ if (!CLG_GetClientAccessReportByIndex(i, req_reset, req_min_hits, &report, &now))
continue;
client = &tx_message->data.client_accesses_by_index.clients[j++];
all*, *deny*, and *deny all* commands specified either via *chronyc*, or in
*chronyd*'s configuration file.
-[[clients]]*clients* [*-r*]::
+[[clients]]*clients* [*-p* _packets_] *[*-r*]::
This command shows a list of clients that have accessed the server, through
either the NTP or command ports. It does not include accesses over
the Unix domain command socket.
+
-If the *-r* option is specified, *chronyd* will reset the counters of received
-and dropped packets after reporting the current values.
+The *-p* option specifies the minimum number of received NTP or command
+packets needed to include a client in the list. The default value is 0, i.e.
+all clients are reported. If the *-r* option is specified, *chronyd* will reset
+the counters of received and dropped packets after reporting the current
+values.
+
An example of the output is:
+