📄 ntp_request.c
字号:
/* * ntp_request.c - respond to information requests */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include "ntpd.h"#include "ntp_io.h"#include "ntp_request.h"#include "ntp_control.h"#include "ntp_refclock.h"#include "ntp_if.h"#include "ntp_stdlib.h"#include <stdio.h>#include <stddef.h>#include <signal.h>#include <netinet/in.h>#include <arpa/inet.h>#include "recvbuff.h"#ifdef KERNEL_PLL#include "ntp_syscall.h"#endif /* KERNEL_PLL *//* * Structure to hold request procedure information */#define NOAUTH 0#define AUTH 1#define NO_REQUEST (-1)/* * Because we now have v6 addresses in the messages, we need to compensate * for the larger size. Therefore, we introduce the alternate size to * keep us friendly with older implementations. A little ugly. */static int client_v6_capable = 0; /* the client can handle longer messages */#define v6sizeof(type) (client_v6_capable ? sizeof(type) : v4sizeof(type))struct req_proc { short request_code; /* defined request code */ short needs_auth; /* true when authentication needed */ short sizeofitem; /* size of request data item (older size)*/ short v6_sizeofitem; /* size of request data item (new size)*/ void (*handler) P((struct sockaddr_storage *, struct interface *, struct req_pkt *)); /* routine to handle request */};/* * Universal request codes */static struct req_proc univ_codes[] = { { NO_REQUEST, NOAUTH, 0, 0 }};static void req_ack P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));static char * prepare_pkt P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_int));static char * more_pkt P((void));static void flush_pkt P((void));static void peer_list P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void peer_list_sum P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void peer_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void peer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void sys_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void sys_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void mem_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void io_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void timer_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void loop_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_conf P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_unconf P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void set_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void clr_sys_flag P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void setclr_flags P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));static void list_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_resaddflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_ressubflags P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_unrestrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_restrict P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));static void mon_getlist_0 P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void mon_getlist_1 P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void reset_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void reset_peer P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_key_reread P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void trust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void untrust_key P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_trustkey P((struct sockaddr_storage *, struct interface *, struct req_pkt *, u_long));static void get_auth_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void reset_auth_stats P((void));static void req_get_traps P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void req_set_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void req_clr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void do_setclr_trap P((struct sockaddr_storage *, struct interface *, struct req_pkt *, int));static void set_request_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void set_control_keyid P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void get_ctl_stats P((struct sockaddr_storage *, struct interface *, struct req_pkt *));#ifdef KERNEL_PLLstatic void get_kernel_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));#endif /* KERNEL_PLL */#ifdef REFCLOCKstatic void get_clock_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));static void set_clock_fudge P((struct sockaddr_storage *, struct interface *, struct req_pkt *));#endif /* REFCLOCK */#ifdef REFCLOCKstatic void get_clkbug_info P((struct sockaddr_storage *, struct interface *, struct req_pkt *));#endif /* REFCLOCK *//* * ntpd request codes */static struct req_proc ntp_codes[] = { { REQ_PEER_LIST, NOAUTH, 0, 0, peer_list }, { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, peer_list_sum }, { REQ_PEER_INFO, NOAUTH, v4sizeof(struct info_peer_list), sizeof(struct info_peer_list), peer_info}, { REQ_PEER_STATS, NOAUTH, v4sizeof(struct info_peer_list), sizeof(struct info_peer_list), peer_stats}, { REQ_SYS_INFO, NOAUTH, 0, 0, sys_info }, { REQ_SYS_STATS, NOAUTH, 0, 0, sys_stats }, { REQ_IO_STATS, NOAUTH, 0, 0, io_stats }, { REQ_MEM_STATS, NOAUTH, 0, 0, mem_stats }, { REQ_LOOP_INFO, NOAUTH, 0, 0, loop_info }, { REQ_TIMER_STATS, NOAUTH, 0, 0, timer_stats }, { REQ_CONFIG, AUTH, v4sizeof(struct conf_peer), sizeof(struct conf_peer), do_conf }, { REQ_UNCONFIG, AUTH, v4sizeof(struct conf_unpeer), sizeof(struct conf_unpeer), do_unconf }, { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), sizeof(struct conf_sys_flags), set_sys_flag }, { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), sizeof(struct conf_sys_flags), clr_sys_flag }, { REQ_GET_RESTRICT, NOAUTH, 0, 0, list_restrict }, { REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict), sizeof(struct conf_restrict), do_resaddflags }, { REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict), sizeof(struct conf_restrict), do_ressubflags }, { REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict), sizeof(struct conf_restrict), do_unrestrict }, { REQ_MON_GETLIST, NOAUTH, 0, 0, mon_getlist_0 }, { REQ_MON_GETLIST_1, NOAUTH, 0, 0, mon_getlist_1 }, { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats }, { REQ_RESET_PEER, AUTH, v4sizeof(struct conf_unpeer), sizeof(struct conf_unpeer), reset_peer }, { REQ_REREAD_KEYS, AUTH, 0, 0, do_key_reread }, { REQ_TRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), trust_key }, { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key }, { REQ_AUTHINFO, NOAUTH, 0, 0, get_auth_info }, { REQ_TRAPS, NOAUTH, 0, 0, req_get_traps }, { REQ_ADD_TRAP, AUTH, v4sizeof(struct conf_trap), sizeof(struct conf_trap), req_set_trap }, { REQ_CLR_TRAP, AUTH, v4sizeof(struct conf_trap), sizeof(struct conf_trap), req_clr_trap }, { REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long), set_request_keyid }, { REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long), set_control_keyid }, { REQ_GET_CTLSTATS, NOAUTH, 0, 0, get_ctl_stats },#ifdef KERNEL_PLL { REQ_GET_KERNEL, NOAUTH, 0, 0, get_kernel_info },#endif#ifdef REFCLOCK { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), get_clock_info }, { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), sizeof(struct conf_fudge), set_clock_fudge }, { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), get_clkbug_info },#endif { NO_REQUEST, NOAUTH, 0, 0, 0 }};/* * Authentication keyid used to authenticate requests. Zero means we * don't allow writing anything. */keyid_t info_auth_keyid;/* * Statistic counters to keep track of requests and responses. */u_long numrequests; /* number of requests we've received */u_long numresppkts; /* number of resp packets sent with data */u_long errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed *//* by the error code *//* * A hack. To keep the authentication module clear of ntp-ism's, we * include a time reset variable for its stats here. */static u_long auth_timereset;/* * 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 resp_pkt rpkt;static int reqver;static int seqno;static int nitems;static int itemsize;static int databytes;static char exbuf[RESP_DATA_SIZE];static int usingexbuf;static struct sockaddr_storage *toaddr;static struct interface *frominter;/* * init_request - initialize request data */voidinit_request (void){ int i; numrequests = 0; numresppkts = 0; auth_timereset = 0; info_auth_keyid = 0; /* by default, can't do this */ for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++) errorcounter[i] = 0;}/* * req_ack - acknowledge request with no data */static voidreq_ack( struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *inpkt, int errcode ){ /* * fill in the fields */ rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); rpkt.auth_seq = AUTH_SEQ(0, 0); rpkt.implementation = inpkt->implementation; rpkt.request = inpkt->request; rpkt.err_nitems = ERR_NITEMS(errcode, 0); rpkt.mbz_itemsize = MBZ_ITEMSIZE(0); /* * send packet and bump counters */ sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE); errorcounter[errcode]++;}/* * prepare_pkt - prepare response packet for transmission, return pointer * to storage for data item. */static char *prepare_pkt( struct sockaddr_storage *srcadr, struct interface *inter, struct req_pkt *pkt, u_int structsize ){#ifdef DEBUG if (debug > 3) printf("request: preparing pkt\n");#endif /* * Fill in the implementation, request and itemsize fields * since these won't change. */ rpkt.implementation = pkt->implementation; rpkt.request = pkt->request; rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize); /* * Compute the static data needed to carry on. */ toaddr = srcadr; frominter = inter; seqno = 0; nitems = 0; itemsize = structsize; databytes = 0; usingexbuf = 0; /* * return the beginning of the packet buffer. */ return &rpkt.data[0];}/* * more_pkt - return a data pointer for a new item. */static char *more_pkt(void){ /* * If we were using the extra buffer, send the packet. */ if (usingexbuf) {#ifdef DEBUG if (debug > 2) printf("request: sending pkt\n");#endif rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver); rpkt.auth_seq = AUTH_SEQ(0, seqno); rpkt.err_nitems = htons((u_short)nitems); sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE+databytes); numresppkts++; /* * Copy data out of exbuf into the packet. */ memmove(&rpkt.data[0], exbuf, (unsigned)itemsize); seqno++; databytes = 0; nitems = 0; usingexbuf = 0; } databytes += itemsize; nitems++; if (databytes + itemsize <= RESP_DATA_SIZE) {#ifdef DEBUG if (debug > 3) printf("request: giving him more data\n");#endif /* * More room in packet. Give him the * next address. */ return &rpkt.data[databytes]; } else { /* * No room in packet. Give him the extra * buffer unless this was the last in the sequence. */#ifdef DEBUG if (debug > 3) printf("request: into extra buffer\n");#endif if (seqno == MAXSEQ) return (char *)0; else { usingexbuf = 1; return exbuf; } }}/* * flush_pkt - we're done, return remaining information. */static voidflush_pkt(void){#ifdef DEBUG if (debug > 2) printf("request: flushing packet, %d items\n", nitems);#endif /* * Must send the last packet. If nothing in here and nothing * has been sent, send an error saying no data to be found. */ if (seqno == 0 && nitems == 0) req_ack(toaddr, frominter, (struct req_pkt *)&rpkt, INFO_ERR_NODATA); else { rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); rpkt.auth_seq = AUTH_SEQ(0, seqno); rpkt.err_nitems = htons((u_short)nitems); sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE+databytes); numresppkts++; }}/* * process_private - process private mode (7) packets */voidprocess_private( struct recvbuf *rbufp, int mod_okay ){ struct req_pkt *inpkt; struct req_pkt_tail *tailinpkt; struct sockaddr_storage *srcadr; struct interface *inter; struct req_proc *proc; int ec; short temp_size; /* * Initialize pointers, for convenience */ inpkt = (struct req_pkt *)&rbufp->recv_pkt; srcadr = &rbufp->recv_srcadr; inter = rbufp->dstadr;#ifdef DEBUG if (debug > 2) printf("process_private: impl %d req %d\n", inpkt->implementation, inpkt->request);#endif /* * Do some sanity checks on the packet. Return a format * error if it fails. */ ec = 0; if ( (++ec, ISRESPONSE(inpkt->rm_vn_mode)) || (++ec, ISMORE(inpkt->rm_vn_mode)) || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION) || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION) || (++ec, INFO_SEQ(inpkt->auth_seq) != 0) || (++ec, INFO_ERR(inpkt->err_nitems) != 0) || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0) || (++ec, rbufp->recv_length < REQ_LEN_HDR) ) { msyslog(LOG_ERR, "process_private: INFO_ERR_FMT: test %d failed, pkt from %s", ec, stoa(srcadr)); req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); return; } reqver = INFO_VERSION(inpkt->rm_vn_mode); /* * Get the appropriate procedure list to search. */ if (inpkt->implementation == IMPL_UNIV) proc = univ_codes; else if ((inpkt->implementation == IMPL_XNTPD) || (inpkt->implementation == IMPL_XNTPD_OLD)) proc = ntp_codes; else { req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL); return; } /* * Search the list for the request codes. If it isn't one * we know, return an error. */ while (proc->request_code != NO_REQUEST) { if (proc->request_code == (short) inpkt->request) break; proc++; } if (proc->request_code == NO_REQUEST) { req_ack(srcadr, inter, inpkt, INFO_ERR_REQ); return; }#ifdef DEBUG if (debug > 3) printf("found request in tables\n");#endif /* * If we need data, check to see if we have some. If we * don't, check to see that there is none (picky, picky). */ /* This part is a bit tricky, we want to be sure that the size * returned is either the old or the new size. We also can find * out if the client can accept both types of messages this way. * * Handle the exception of REQ_CONFIG. It can have two data sizes. */ temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize); if ((temp_size != proc->sizeofitem && temp_size != proc->v6_sizeofitem) && !(inpkt->implementation == IMPL_XNTPD && inpkt->request == REQ_CONFIG && temp_size == sizeof(struct old_conf_peer))) {#ifdef DEBUG if (debug > 2) printf("process_private: wrong item size, received %d, should be %d or %d\n", temp_size, proc->sizeofitem, proc->v6_sizeofitem);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -