📄 ntp_control.c
字号:
/* * ntp_control.c - respond to control messages and send async traps */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "ntpd.h"#include "ntp_io.h"#include "ntp_refclock.h"#include "ntp_control.h"#include "ntp_unixtime.h"#include "ntp_stdlib.h"#include <stdio.h>#include <ctype.h>#include <signal.h>#include <netinet/in.h>#include <arpa/inet.h>/* * Structure to hold request procedure information */#define NOAUTH 0#define AUTH 1#define NO_REQUEST (-1)struct ctl_proc { short control_code; /* defined request code */ u_short flags; /* flags word */ void (*handler) P((struct recvbuf *, int)); /* handle request */};/* * Only one flag. Authentication required or not. */#define NOAUTH 0#define AUTH 1/* * Request processing routines */static void ctl_error P((int));#ifdef REFCLOCKstatic u_short ctlclkstatus P((struct refclockstat *));#endifstatic void ctl_flushpkt P((int));static void ctl_putdata P((const char *, unsigned int, int));static void ctl_putstr P((const char *, const char *, unsigned int));static void ctl_putdbl P((const char *, double));static void ctl_putuint P((const char *, u_long));static void ctl_puthex P((const char *, u_long));static void ctl_putint P((const char *, long));static void ctl_putts P((const char *, l_fp *));static void ctl_putadr P((const char *, u_int32, struct sockaddr_storage*));static void ctl_putid P((const char *, char *));static void ctl_putarray P((const char *, double *, int));static void ctl_putsys P((int));static void ctl_putpeer P((int, struct peer *));static void ctl_putfs P((const char *, tstamp_t));#ifdef REFCLOCKstatic void ctl_putclock P((int, struct refclockstat *, int));#endif /* REFCLOCK */static struct ctl_var *ctl_getitem P((struct ctl_var *, char **));static u_long count_var P((struct ctl_var *));static void control_unspec P((struct recvbuf *, int));static void read_status P((struct recvbuf *, int));static void read_variables P((struct recvbuf *, int));static void write_variables P((struct recvbuf *, int));static void read_clock_status P((struct recvbuf *, int));static void write_clock_status P((struct recvbuf *, int));static void set_trap P((struct recvbuf *, int));static void unset_trap P((struct recvbuf *, int));static struct ctl_trap *ctlfindtrap P((struct sockaddr_storage *, struct interface *));static struct ctl_proc control_codes[] = { { CTL_OP_UNSPEC, NOAUTH, control_unspec }, { CTL_OP_READSTAT, NOAUTH, read_status }, { CTL_OP_READVAR, NOAUTH, read_variables }, { CTL_OP_WRITEVAR, AUTH, write_variables }, { CTL_OP_READCLOCK, NOAUTH, read_clock_status }, { CTL_OP_WRITECLOCK, NOAUTH, write_clock_status }, { CTL_OP_SETTRAP, NOAUTH, set_trap }, { CTL_OP_UNSETTRAP, NOAUTH, unset_trap }, { NO_REQUEST, 0 }};/* * System variable values. The array can be indexed by the variable * index to find the textual name. */static struct ctl_var sys_var[] = { { 0, PADDING, "" }, /* 0 */ { CS_LEAP, RW, "leap" }, /* 1 */ { CS_STRATUM, RO, "stratum" }, /* 2 */ { CS_PRECISION, RO, "precision" }, /* 3 */ { CS_ROOTDELAY, RO, "rootdelay" }, /* 4 */ { CS_ROOTDISPERSION, RO, "rootdispersion" }, /* 5 */ { CS_REFID, RO, "refid" }, /* 6 */ { CS_REFTIME, RO, "reftime" }, /* 7 */ { CS_POLL, RO, "poll" }, /* 8 */ { CS_PEERID, RO, "peer" }, /* 9 */ { CS_STATE, RO, "state" }, /* 10 */ { CS_OFFSET, RO, "offset" }, /* 11 */ { CS_DRIFT, RO, "frequency" }, /* 12 */ { CS_JITTER, RO, "jitter" }, /* 13 */ { CS_ERROR, RO, "noise" }, /* 14 */ { CS_CLOCK, RO, "clock" }, /* 15 */ { CS_PROCESSOR, RO, "processor" }, /* 16 */ { CS_SYSTEM, RO, "system" }, /* 17 */ { CS_VERSION, RO, "version" }, /* 18 */ { CS_STABIL, RO, "stability" }, /* 19 */ { CS_VARLIST, RO, "sys_var_list" }, /* 20 */#ifdef OPENSSL { CS_FLAGS, RO, "flags" }, /* 21 */ { CS_HOST, RO, "hostname" }, /* 22 */ { CS_PUBLIC, RO, "update" }, /* 23 */ { CS_CERTIF, RO, "cert" }, /* 24 */ { CS_REVTIME, RO, "expire" }, /* 25 */ { CS_LEAPTAB, RO, "leapsec" }, /* 26 */ { CS_TAI, RO, "tai" }, /* 27 */ { CS_DIGEST, RO, "signature" }, /* 28 */ { CS_IDENT, RO, "ident" }, /* 29 */ { CS_REVOKE, RO, "expire" }, /* 30 */#endif /* OPENSSL */ { 0, EOV, "" } /* 21/31 */};static struct ctl_var *ext_sys_var = (struct ctl_var *)0;/* * System variables we print by default (in fuzzball order, * more-or-less) */static u_char def_sys_var[] = { CS_VERSION, CS_PROCESSOR, CS_SYSTEM, CS_LEAP, CS_STRATUM, CS_PRECISION, CS_ROOTDELAY, CS_ROOTDISPERSION, CS_PEERID, CS_REFID, CS_REFTIME, CS_POLL, CS_CLOCK, CS_STATE, CS_OFFSET, CS_DRIFT, CS_JITTER, CS_ERROR, CS_STABIL,#ifdef OPENSSL CS_HOST, CS_DIGEST, CS_FLAGS, CS_PUBLIC, CS_IDENT, CS_LEAPTAB, CS_TAI, CS_CERTIF,#endif /* OPENSSL */ 0};/* * Peer variable list */static struct ctl_var peer_var[] = { { 0, PADDING, "" }, /* 0 */ { CP_CONFIG, RO, "config" }, /* 1 */ { CP_AUTHENABLE, RO, "authenable" }, /* 2 */ { CP_AUTHENTIC, RO, "authentic" }, /* 3 */ { CP_SRCADR, RO, "srcadr" }, /* 4 */ { CP_SRCPORT, RO, "srcport" }, /* 5 */ { CP_DSTADR, RO, "dstadr" }, /* 6 */ { CP_DSTPORT, RO, "dstport" }, /* 7 */ { CP_LEAP, RO, "leap" }, /* 8 */ { CP_HMODE, RO, "hmode" }, /* 9 */ { CP_STRATUM, RO, "stratum" }, /* 10 */ { CP_PPOLL, RO, "ppoll" }, /* 11 */ { CP_HPOLL, RO, "hpoll" }, /* 12 */ { CP_PRECISION, RO, "precision" }, /* 13 */ { CP_ROOTDELAY, RO, "rootdelay" }, /* 14 */ { CP_ROOTDISPERSION, RO, "rootdispersion" }, /* 15 */ { CP_REFID, RO, "refid" }, /* 16 */ { CP_REFTIME, RO, "reftime" }, /* 17 */ { CP_ORG, RO, "org" }, /* 18 */ { CP_REC, RO, "rec" }, /* 19 */ { CP_XMT, RO, "xmt" }, /* 20 */ { CP_REACH, RO, "reach" }, /* 21 */ { CP_UNREACH, RO, "unreach" }, /* 22 */ { CP_TIMER, RO, "timer" }, /* 23 */ { CP_DELAY, RO, "delay" }, /* 24 */ { CP_OFFSET, RO, "offset" }, /* 25 */ { CP_JITTER, RO, "jitter" }, /* 26 */ { CP_DISPERSION, RO, "dispersion" }, /* 27 */ { CP_KEYID, RO, "keyid" }, /* 28 */ { CP_FILTDELAY, RO, "filtdelay=" }, /* 29 */ { CP_FILTOFFSET, RO, "filtoffset=" }, /* 30 */ { CP_PMODE, RO, "pmode" }, /* 31 */ { CP_RECEIVED, RO, "received"}, /* 32 */ { CP_SENT, RO, "sent" }, /* 33 */ { CP_FILTERROR, RO, "filtdisp=" }, /* 34 */ { CP_FLASH, RO, "flash" }, /* 35 */ { CP_TTL, RO, "ttl" }, /* 36 */ { CP_VARLIST, RO, "peer_var_list" }, /* 37 */#ifdef OPENSSL { CP_FLAGS, RO, "flags" }, /* 38 */ { CP_HOST, RO, "hostname" }, /* 39 */ { CP_VALID, RO, "valid" }, /* 40 */ { CP_INITSEQ, RO, "initsequence" }, /* 41 */ { CP_INITKEY, RO, "initkey" }, /* 42 */ { CP_INITTSP, RO, "timestamp" }, /* 43 */ { CP_DIGEST, RO, "signature" }, /* 44 */ { CP_IDENT, RO, "trust" }, /* 45 */#endif /* OPENSSL */ { 0, EOV, "" } /* 38/46 */};/* * Peer variables we print by default */static u_char def_peer_var[] = { CP_SRCADR, CP_SRCPORT, CP_DSTADR, CP_DSTPORT, CP_LEAP, CP_STRATUM, CP_PRECISION, CP_ROOTDELAY, CP_ROOTDISPERSION, CP_REFID, CP_REACH, CP_UNREACH, CP_HMODE, CP_PMODE, CP_HPOLL, CP_PPOLL, CP_FLASH, CP_KEYID, CP_TTL, CP_OFFSET, CP_DELAY, CP_DISPERSION, CP_JITTER, CP_REFTIME, CP_ORG, CP_REC, CP_XMT, CP_FILTDELAY, CP_FILTOFFSET, CP_FILTERROR,#ifdef OPENSSL CP_HOST, CP_DIGEST, CP_VALID, CP_FLAGS, CP_IDENT, CP_INITSEQ,#endif /* OPENSSL */ 0};#ifdef REFCLOCK/* * Clock variable list */static struct ctl_var clock_var[] = { { 0, PADDING, "" }, /* 0 */ { CC_TYPE, RO, "type" }, /* 1 */ { CC_TIMECODE, RO, "timecode" }, /* 2 */ { CC_POLL, RO, "poll" }, /* 3 */ { CC_NOREPLY, RO, "noreply" }, /* 4 */ { CC_BADFORMAT, RO, "badformat" }, /* 5 */ { CC_BADDATA, RO, "baddata" }, /* 6 */ { CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */ { CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */ { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */ { CC_FUDGEVAL2, RO, "refid" }, /* 10 */ { CC_FLAGS, RO, "flags" }, /* 11 */ { CC_DEVICE, RO, "device" }, /* 12 */ { CC_VARLIST, RO, "clock_var_list" }, /* 13 */ { 0, EOV, "" } /* 14 */};/* * Clock variables printed by default */static u_char def_clock_var[] = { CC_DEVICE, CC_TYPE, /* won't be output if device = known */ CC_TIMECODE, CC_POLL, CC_NOREPLY, CC_BADFORMAT, CC_BADDATA, CC_FUDGETIME1, CC_FUDGETIME2, CC_FUDGEVAL1, CC_FUDGEVAL2, CC_FLAGS, 0};#endif/* * System and processor definitions. */#ifndef HAVE_UNAME# ifndef STR_SYSTEM# define STR_SYSTEM "UNIX"# endif# ifndef STR_PROCESSOR# define STR_PROCESSOR "unknown"# endifstatic char str_system[] = STR_SYSTEM;static char str_processor[] = STR_PROCESSOR;#else# include <sys/utsname.h>static struct utsname utsnamebuf;#endif /* HAVE_UNAME *//* * Trap structures. We only allow a few of these, and send a copy of * each async message to each live one. Traps time out after an hour, it * is up to the trap receipient to keep resetting it to avoid being * timed out. *//* ntp_request.c */struct ctl_trap ctl_trap[CTL_MAXTRAPS];int num_ctl_traps;/* * Type bits, for ctlsettrap() call. */#define TRAP_TYPE_CONFIG 0 /* used by configuration code */#define TRAP_TYPE_PRIO 1 /* priority trap */#define TRAP_TYPE_NONPRIO 2 /* nonpriority trap *//* * List relating reference clock types to control message time sources. * Index by the reference clock type. This list will only be used iff * the reference clock driver doesn't set peer->sstclktype to something * different than CTL_SST_TS_UNSPEC. */static u_char clocktypes[] = { CTL_SST_TS_NTP, /* REFCLK_NONE (0) */ CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */ CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */ CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */ CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */ CTL_SST_TS_UHF, /* REFCLK_TRUETIME (5) */ CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */ CTL_SST_TS_HF, /* REFCLK_CHU (7) */ CTL_SST_TS_LF, /* REFCLOCK_PARSE (default) (8) */ CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */ CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */ CTL_SST_TS_UHF, /* REFCLK_GPS_ARBITER (11) */ CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */ CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */ CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */ CTL_SST_TS_NTP, /* not used (15) */ CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */ CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */ CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACTS (18) */ CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */ CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */ CTL_SST_TS_UHF, /* REFCLK_GPS_VME (21) */ CTL_SST_TS_ATOM, /* REFCLK_ATOM_PPS (22) */ CTL_SST_TS_NTP, /* not used (23) */ CTL_SST_TS_NTP, /* not used (24) */ CTL_SST_TS_NTP, /* not used (25) */ CTL_SST_TS_UHF, /* REFCLK_GPS_HP (26) */ CTL_SST_TS_TELEPHONE, /* REFCLK_ARCRON_MSF (27) */ CTL_SST_TS_TELEPHONE, /* REFCLK_SHM (28) */ CTL_SST_TS_UHF, /* REFCLK_PALISADE (29) */ CTL_SST_TS_UHF, /* REFCLK_ONCORE (30) */ CTL_SST_TS_UHF, /* REFCLK_JUPITER (31) */ CTL_SST_TS_LF, /* REFCLK_CHRONOLOG (32) */ CTL_SST_TS_LF, /* REFCLK_DUMBCLOCK (33) */ CTL_SST_TS_LF, /* REFCLK_ULINK (34) */ CTL_SST_TS_LF, /* REFCLK_PCF (35) */ CTL_SST_TS_LF, /* REFCLK_WWV (36) */ CTL_SST_TS_LF, /* REFCLK_FG (37) */ CTL_SST_TS_UHF, /* REFCLK_HOPF_SERIAL (38) */ CTL_SST_TS_UHF, /* REFCLK_HOPF_PCI (39) */ CTL_SST_TS_LF, /* REFCLK_JJY (40) */ CTL_SST_TS_UHF, /* REFCLK_TT560 (41) */ CTL_SST_TS_UHF, /* REFCLK_ZYFER (42) */ CTL_SST_TS_UHF, /* REFCLK_RIPENCC (43) */ CTL_SST_TS_UHF, /* REFCLK_NEOCLOCK4X (44) */};/* * Keyid used for authenticating write requests. */keyid_t ctl_auth_keyid;/* * We keep track of the last error reported by the system internally */static u_char ctl_sys_last_event;static u_char ctl_sys_num_events;/* * Statistic counters to keep track of requests and responses. */u_long ctltimereset; /* time stats reset */u_long numctlreq; /* number of requests we've received */u_long numctlbadpkts; /* number of bad control packets */u_long numctlresponses; /* number of resp packets sent with data */u_long numctlfrags; /* number of fragments sent */u_long numctlerrors; /* number of error responses sent */u_long numctltooshort; /* number of too short input packets */u_long numctlinputresp; /* number of responses on input */u_long numctlinputfrag; /* number of fragments on input */u_long numctlinputerr; /* number of input pkts with err bit set */u_long numctlbadoffset; /* number of input pkts with nonzero offset */u_long numctlbadversion; /* number of input pkts with unknown version */u_long numctldatatooshort; /* data too short for count */u_long numctlbadop; /* bad op code found in packet */u_long numasyncmsgs; /* number of async messages we've sent *//* * Response packet used by these routines. Also some state information * so that we can handle packet formatting within a common set of * subroutines. Note we try to enter data in place whenever possible, * but the need to set the more bit correctly means we occasionally * use the extra buffer and copy. */static struct ntp_control rpkt;static u_char res_version;static u_char res_opcode;static associd_t res_associd;static int res_offset;static u_char * datapt;static u_char * dataend;static int datalinelen;static int datanotbinflag;static struct sockaddr_storage *rmt_addr;static struct interface *lcl_inter;static u_char res_authenticate;static u_char res_authokay;static keyid_t res_keyid;#define MAXDATALINELEN (72)static u_char res_async; /* set to 1 if this is async trap response *//* * Pointers for saving state when decoding request packets */static char *reqpt;static char *reqend;/* * init_control - initialize request data */voidinit_control(void){ int i;#ifdef HAVE_UNAME uname(&utsnamebuf);#endif /* HAVE_UNAME */ ctl_clr_stats(); ctl_auth_keyid = 0; ctl_sys_last_event = EVNT_UNSPEC; ctl_sys_num_events = 0; num_ctl_traps = 0; for (i = 0; i < CTL_MAXTRAPS; i++) ctl_trap[i].tr_flags = 0;}/* * ctl_error - send an error response for the current request */static voidctl_error( int errcode ){#ifdef DEBUG if (debug >= 4) printf("sending control error %d\n", errcode);#endif /* * Fill in the fields. We assume rpkt.sequence and rpkt.associd * have already been filled in. */ rpkt.r_m_e_op = (u_char) (CTL_RESPONSE|CTL_ERROR|(res_opcode & CTL_OP_MASK)); rpkt.status = htons((u_short) ((errcode<<8) & 0xff00)); rpkt.count = 0; /* * send packet and bump counters */ if (res_authenticate && sys_authenticate) { int maclen; *(u_int32 *)((u_char *)&rpkt + CTL_HEADER_LEN) = htonl(res_keyid); maclen = authencrypt(res_keyid, (u_int32 *)&rpkt, CTL_HEADER_LEN); sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt, CTL_HEADER_LEN + maclen); } else { sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt, CTL_HEADER_LEN); } numctlerrors++;}/* * process_control - process an incoming control message */voidprocess_control( struct recvbuf *rbufp, int restrict_mask ){ register struct ntp_control *pkt; register int req_count; register int req_data; register struct ctl_proc *cc; int properlen; int maclen;#ifdef DEBUG if (debug > 2) printf("in process_control()\n");#endif /* * Save the addresses for error responses */ numctlreq++; rmt_addr = &rbufp->recv_srcadr; lcl_inter = rbufp->dstadr; pkt = (struct ntp_control *)&rbufp->recv_pkt; /* * If the length is less than required for the header, or * it is a response or a fragment, ignore this. */ if (rbufp->recv_length < CTL_HEADER_LEN || pkt->r_m_e_op & (CTL_RESPONSE|CTL_MORE|CTL_ERROR) || pkt->offset != 0) {#ifdef DEBUG if (debug) printf("invalid format in control packet\n");#endif if (rbufp->recv_length < CTL_HEADER_LEN) numctltooshort++; if (pkt->r_m_e_op & CTL_RESPONSE) numctlinputresp++; if (pkt->r_m_e_op & CTL_MORE) numctlinputfrag++; if (pkt->r_m_e_op & CTL_ERROR) numctlinputerr++; if (pkt->offset != 0) numctlbadoffset++; return; } res_version = PKT_VERSION(pkt->li_vn_mode); if (res_version > NTP_VERSION || res_version < NTP_OLDVERSION) {#ifdef DEBUG if (debug) printf("unknown version %d in control packet\n", res_version);#endif numctlbadversion++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -