File: monlist.c

package info (click to toggle)
lbcd 3.5.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,708 kB
  • sloc: ansic: 11,073; sh: 1,816; perl: 503; makefile: 165
file content (154 lines) | stat: -rw-r--r-- 4,276 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Utility code to return the number of NTP peers of a system.
 *
 * This code is xntpdc's monlist command butchered and packaged in a single
 * source file.
 *
 * Modified fom xntpd source by Larry Schwimmer
 * Copyright 1992-1997 University of Delaware
 * Copyright 1997, 1998, 2008, 2012
 *     The Board of Trustees of the Leland Stanford Junior University
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appears in all copies and that
 * both the copyright notice and this permission notice appear in supporting
 * documentation, and that the name University of Delaware not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission. The University of Delaware makes no
 * representations about the suitability this software for any purpose. It is
 * provided "as is" without express or implied warranty.
 */

#include <config.h>
#include <portable/socket.h>
#include <portable/system.h>

#include <ctype.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#include <sys/time.h>

#include <modules/monlist.h>

/* The maximum packets of rely to read from the server. */
#define MAXPACKETS 100


/*
 * Format and send a request packet.
 */
static int
sendrequest(int sd, int implcode, int reqcode)
{
    struct req_pkt qpkt;

    memset(&qpkt, 0, sizeof qpkt);
    qpkt.rm_vn_mode = RM_VN_MODE(0, 0);
    qpkt.implementation = (uint8_t) implcode;
    qpkt.request = (uint8_t) reqcode;
    qpkt.err_nitems = ERR_NITEMS(0, 0);
    qpkt.mbz_itemsize = MBZ_ITEMSIZE(0);
    qpkt.auth_seq = AUTH_SEQ(0, 0);

    if (send(sd, &qpkt, REQ_LEN_NOMAC, 0) == -1)
        return -1;
    return 0;
}


/*
 * Get number of entries in the first packet.
 */
static int
getresponse(int sd, int implcode, int reqcode, int *ritems, int timeout)
{
    struct resp_pkt rpkt;
    struct timeval tv = { 0, 0 };
    int seq;
    fd_set fds;
    int n;
    int seenpacket[MAXPACKETS];
    int lastseq = 999;
    int numrecv = 0;

    tv.tv_sec = timeout;
    *ritems = 0;
    memset(seenpacket, 0, sizeof(seenpacket));

    /* Receive reply packet. */
    while (1) {
        FD_ZERO(&fds);
        FD_SET(sd, &fds);
        n = select(sd + 1, &fds, NULL, NULL, &tv);
        if (n < 1)
            return -1;
        n = recv(sd, (char *)&rpkt, sizeof(rpkt), 0);
        if (n == -1)
            return -1;

        /* Check for format errors. */
        if ((n < RESP_HEADER_SIZE)
            || (INFO_VERSION(rpkt.rm_vn_mode) != NTP_VERSION)
            || (INFO_MODE(rpkt.rm_vn_mode) != MODE_PRIVATE)
            || (INFO_IS_AUTH(rpkt.auth_seq))
            || (!ISRESPONSE(rpkt.rm_vn_mode))
            || (INFO_MBZ(rpkt.mbz_itemsize) != 0))
            continue;

        /* Check implementation/request.  Could be old data getting to us. */
        if (rpkt.implementation != implcode || rpkt.request != reqcode)
            continue;

        /* Check the error code.  If non-zero, return it. */
        if (INFO_ERR(rpkt.err_nitems) != INFO_OKAY)
            return INFO_ERR(rpkt.err_nitems);

        /* If it isn't the first packet, we don't care. */
        seq = INFO_SEQ(rpkt.auth_seq);
        if (seq >= MAXPACKETS)
            continue;
        if (seenpacket[seq])
            continue;
        seenpacket[seq]++;

        /* Collect items and size.  Make sure they make sense. */
        *ritems += INFO_NITEMS(rpkt.err_nitems);

        /* Check if end of sequence packet. */
        if (!ISMORE(rpkt.rm_vn_mode)) {
            if (lastseq != 999)
                continue;
            lastseq = seq;
        }

        /* Check if done. */
        numrecv++;
        if (numrecv <= lastseq)
            continue;
        break;
    }
    return 0;
}


/*
 * Return number of NTP peers for a machine.
 */
int
monlist(int sd, int timeout)
{
    int res, peers;

    /* Send monlist request. */
    res = sendrequest(sd, IMPL_XNTPD, REQ_MON_GETLIST);
    if (res != 0)
        return -1;

    /* Get the monlist response. */
    res = getresponse(sd, IMPL_XNTPD, REQ_MON_GETLIST, &peers, timeout);
    if (res != 0)
        return -1;
    return peers;
}