1*9e9fa66aSchristos /* $NetBSD: ntp_request.c,v 1.20 2024/10/01 20:59:51 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_request.c - respond to information requests 5abb0f93cSkardel */ 6abb0f93cSkardel 7abb0f93cSkardel #ifdef HAVE_CONFIG_H 8abb0f93cSkardel # include <config.h> 9abb0f93cSkardel #endif 10abb0f93cSkardel 11abb0f93cSkardel #include "ntpd.h" 12abb0f93cSkardel #include "ntp_io.h" 13abb0f93cSkardel #include "ntp_request.h" 14abb0f93cSkardel #include "ntp_control.h" 15abb0f93cSkardel #include "ntp_refclock.h" 16abb0f93cSkardel #include "ntp_if.h" 17abb0f93cSkardel #include "ntp_stdlib.h" 18abb0f93cSkardel #include "ntp_assert.h" 19abb0f93cSkardel 20abb0f93cSkardel #include <stdio.h> 21abb0f93cSkardel #include <stddef.h> 22abb0f93cSkardel #include <signal.h> 23abb0f93cSkardel #ifdef HAVE_NETINET_IN_H 24abb0f93cSkardel #include <netinet/in.h> 25abb0f93cSkardel #endif 26abb0f93cSkardel #include <arpa/inet.h> 27abb0f93cSkardel 28abb0f93cSkardel #include "recvbuff.h" 29abb0f93cSkardel 30abb0f93cSkardel #ifdef KERNEL_PLL 31abb0f93cSkardel #include "ntp_syscall.h" 32abb0f93cSkardel #endif /* KERNEL_PLL */ 33abb0f93cSkardel 34abb0f93cSkardel /* 35abb0f93cSkardel * Structure to hold request procedure information 36abb0f93cSkardel */ 37abb0f93cSkardel #define NOAUTH 0 38abb0f93cSkardel #define AUTH 1 39abb0f93cSkardel 40abb0f93cSkardel #define NO_REQUEST (-1) 41abb0f93cSkardel /* 42abb0f93cSkardel * Because we now have v6 addresses in the messages, we need to compensate 43abb0f93cSkardel * for the larger size. Therefore, we introduce the alternate size to 44abb0f93cSkardel * keep us friendly with older implementations. A little ugly. 45abb0f93cSkardel */ 46abb0f93cSkardel static int client_v6_capable = 0; /* the client can handle longer messages */ 47abb0f93cSkardel 48abb0f93cSkardel #define v6sizeof(type) (client_v6_capable ? sizeof(type) : v4sizeof(type)) 49abb0f93cSkardel 50abb0f93cSkardel struct req_proc { 51abb0f93cSkardel short request_code; /* defined request code */ 52abb0f93cSkardel short needs_auth; /* true when authentication needed */ 53abb0f93cSkardel short sizeofitem; /* size of request data item (older size)*/ 54abb0f93cSkardel short v6_sizeofitem; /* size of request data item (new size)*/ 552950cc38Schristos void (*handler) (sockaddr_u *, endpt *, 56abb0f93cSkardel struct req_pkt *); /* routine to handle request */ 57abb0f93cSkardel }; 58abb0f93cSkardel 59abb0f93cSkardel /* 60abb0f93cSkardel * Universal request codes 61abb0f93cSkardel */ 622950cc38Schristos static const struct req_proc univ_codes[] = { 63e19314b7Schristos { NO_REQUEST, NOAUTH, 0, 0, NULL } 64abb0f93cSkardel }; 65abb0f93cSkardel 662950cc38Schristos static void req_ack (sockaddr_u *, endpt *, struct req_pkt *, int); 672950cc38Schristos static void * prepare_pkt (sockaddr_u *, endpt *, 68abb0f93cSkardel struct req_pkt *, size_t); 692950cc38Schristos static void * more_pkt (void); 70abb0f93cSkardel static void flush_pkt (void); 712950cc38Schristos static void list_peers (sockaddr_u *, endpt *, struct req_pkt *); 722950cc38Schristos static void list_peers_sum (sockaddr_u *, endpt *, struct req_pkt *); 732950cc38Schristos static void peer_info (sockaddr_u *, endpt *, struct req_pkt *); 742950cc38Schristos static void peer_stats (sockaddr_u *, endpt *, struct req_pkt *); 752950cc38Schristos static void sys_info (sockaddr_u *, endpt *, struct req_pkt *); 762950cc38Schristos static void sys_stats (sockaddr_u *, endpt *, struct req_pkt *); 772950cc38Schristos static void mem_stats (sockaddr_u *, endpt *, struct req_pkt *); 782950cc38Schristos static void io_stats (sockaddr_u *, endpt *, struct req_pkt *); 792950cc38Schristos static void timer_stats (sockaddr_u *, endpt *, struct req_pkt *); 802950cc38Schristos static void loop_info (sockaddr_u *, endpt *, struct req_pkt *); 812950cc38Schristos static void do_conf (sockaddr_u *, endpt *, struct req_pkt *); 822950cc38Schristos static void do_unconf (sockaddr_u *, endpt *, struct req_pkt *); 832950cc38Schristos static void set_sys_flag (sockaddr_u *, endpt *, struct req_pkt *); 842950cc38Schristos static void clr_sys_flag (sockaddr_u *, endpt *, struct req_pkt *); 852950cc38Schristos static void setclr_flags (sockaddr_u *, endpt *, struct req_pkt *, u_long); 86*9e9fa66aSchristos static void list_restrict4 (const struct restrict_4 *, struct info_restrict **); 87*9e9fa66aSchristos static void list_restrict6 (const struct restrict_6 *, struct info_restrict **); 882950cc38Schristos static void list_restrict (sockaddr_u *, endpt *, struct req_pkt *); 892950cc38Schristos static void do_resaddflags (sockaddr_u *, endpt *, struct req_pkt *); 902950cc38Schristos static void do_ressubflags (sockaddr_u *, endpt *, struct req_pkt *); 912950cc38Schristos static void do_unrestrict (sockaddr_u *, endpt *, struct req_pkt *); 924eea345dSchristos static void do_restrict (sockaddr_u *, endpt *, struct req_pkt *, restrict_op); 932950cc38Schristos static void mon_getlist (sockaddr_u *, endpt *, struct req_pkt *); 942950cc38Schristos static void reset_stats (sockaddr_u *, endpt *, struct req_pkt *); 952950cc38Schristos static void reset_peer (sockaddr_u *, endpt *, struct req_pkt *); 962950cc38Schristos static void do_key_reread (sockaddr_u *, endpt *, struct req_pkt *); 972950cc38Schristos static void trust_key (sockaddr_u *, endpt *, struct req_pkt *); 982950cc38Schristos static void untrust_key (sockaddr_u *, endpt *, struct req_pkt *); 992950cc38Schristos static void do_trustkey (sockaddr_u *, endpt *, struct req_pkt *, u_long); 1002950cc38Schristos static void get_auth_info (sockaddr_u *, endpt *, struct req_pkt *); 1012950cc38Schristos static void req_get_traps (sockaddr_u *, endpt *, struct req_pkt *); 1022950cc38Schristos static void req_set_trap (sockaddr_u *, endpt *, struct req_pkt *); 1032950cc38Schristos static void req_clr_trap (sockaddr_u *, endpt *, struct req_pkt *); 1042950cc38Schristos static void do_setclr_trap (sockaddr_u *, endpt *, struct req_pkt *, int); 1052950cc38Schristos static void set_request_keyid (sockaddr_u *, endpt *, struct req_pkt *); 1062950cc38Schristos static void set_control_keyid (sockaddr_u *, endpt *, struct req_pkt *); 1072950cc38Schristos static void get_ctl_stats (sockaddr_u *, endpt *, struct req_pkt *); 1082950cc38Schristos static void get_if_stats (sockaddr_u *, endpt *, struct req_pkt *); 1092950cc38Schristos static void do_if_reload (sockaddr_u *, endpt *, struct req_pkt *); 110abb0f93cSkardel #ifdef KERNEL_PLL 1112950cc38Schristos static void get_kernel_info (sockaddr_u *, endpt *, struct req_pkt *); 112abb0f93cSkardel #endif /* KERNEL_PLL */ 113abb0f93cSkardel #ifdef REFCLOCK 1142950cc38Schristos static void get_clock_info (sockaddr_u *, endpt *, struct req_pkt *); 1152950cc38Schristos static void set_clock_fudge (sockaddr_u *, endpt *, struct req_pkt *); 116abb0f93cSkardel #endif /* REFCLOCK */ 117abb0f93cSkardel #ifdef REFCLOCK 1182950cc38Schristos static void get_clkbug_info (sockaddr_u *, endpt *, struct req_pkt *); 119abb0f93cSkardel #endif /* REFCLOCK */ 120abb0f93cSkardel 121abb0f93cSkardel /* 122abb0f93cSkardel * ntpd request codes 123abb0f93cSkardel */ 1242950cc38Schristos static const struct req_proc ntp_codes[] = { 1252950cc38Schristos { REQ_PEER_LIST, NOAUTH, 0, 0, list_peers }, 1262950cc38Schristos { REQ_PEER_LIST_SUM, NOAUTH, 0, 0, list_peers_sum }, 127abb0f93cSkardel { REQ_PEER_INFO, NOAUTH, v4sizeof(struct info_peer_list), 128abb0f93cSkardel sizeof(struct info_peer_list), peer_info}, 129abb0f93cSkardel { REQ_PEER_STATS, NOAUTH, v4sizeof(struct info_peer_list), 130abb0f93cSkardel sizeof(struct info_peer_list), peer_stats}, 131abb0f93cSkardel { REQ_SYS_INFO, NOAUTH, 0, 0, sys_info }, 132abb0f93cSkardel { REQ_SYS_STATS, NOAUTH, 0, 0, sys_stats }, 133abb0f93cSkardel { REQ_IO_STATS, NOAUTH, 0, 0, io_stats }, 134abb0f93cSkardel { REQ_MEM_STATS, NOAUTH, 0, 0, mem_stats }, 135abb0f93cSkardel { REQ_LOOP_INFO, NOAUTH, 0, 0, loop_info }, 136abb0f93cSkardel { REQ_TIMER_STATS, NOAUTH, 0, 0, timer_stats }, 137abb0f93cSkardel { REQ_CONFIG, AUTH, v4sizeof(struct conf_peer), 138abb0f93cSkardel sizeof(struct conf_peer), do_conf }, 139abb0f93cSkardel { REQ_UNCONFIG, AUTH, v4sizeof(struct conf_unpeer), 140abb0f93cSkardel sizeof(struct conf_unpeer), do_unconf }, 141abb0f93cSkardel { REQ_SET_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), 142abb0f93cSkardel sizeof(struct conf_sys_flags), set_sys_flag }, 143abb0f93cSkardel { REQ_CLR_SYS_FLAG, AUTH, sizeof(struct conf_sys_flags), 144abb0f93cSkardel sizeof(struct conf_sys_flags), clr_sys_flag }, 145abb0f93cSkardel { REQ_GET_RESTRICT, NOAUTH, 0, 0, list_restrict }, 146abb0f93cSkardel { REQ_RESADDFLAGS, AUTH, v4sizeof(struct conf_restrict), 147abb0f93cSkardel sizeof(struct conf_restrict), do_resaddflags }, 148abb0f93cSkardel { REQ_RESSUBFLAGS, AUTH, v4sizeof(struct conf_restrict), 149abb0f93cSkardel sizeof(struct conf_restrict), do_ressubflags }, 150abb0f93cSkardel { REQ_UNRESTRICT, AUTH, v4sizeof(struct conf_restrict), 151abb0f93cSkardel sizeof(struct conf_restrict), do_unrestrict }, 1522950cc38Schristos { REQ_MON_GETLIST, NOAUTH, 0, 0, mon_getlist }, 1532950cc38Schristos { REQ_MON_GETLIST_1, NOAUTH, 0, 0, mon_getlist }, 154abb0f93cSkardel { REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), 0, reset_stats }, 155abb0f93cSkardel { REQ_RESET_PEER, AUTH, v4sizeof(struct conf_unpeer), 156abb0f93cSkardel sizeof(struct conf_unpeer), reset_peer }, 157abb0f93cSkardel { REQ_REREAD_KEYS, AUTH, 0, 0, do_key_reread }, 158abb0f93cSkardel { REQ_TRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), trust_key }, 159abb0f93cSkardel { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), sizeof(u_long), untrust_key }, 160abb0f93cSkardel { REQ_AUTHINFO, NOAUTH, 0, 0, get_auth_info }, 161abb0f93cSkardel { REQ_TRAPS, NOAUTH, 0, 0, req_get_traps }, 162abb0f93cSkardel { REQ_ADD_TRAP, AUTH, v4sizeof(struct conf_trap), 163abb0f93cSkardel sizeof(struct conf_trap), req_set_trap }, 164abb0f93cSkardel { REQ_CLR_TRAP, AUTH, v4sizeof(struct conf_trap), 165abb0f93cSkardel sizeof(struct conf_trap), req_clr_trap }, 166abb0f93cSkardel { REQ_REQUEST_KEY, AUTH, sizeof(u_long), sizeof(u_long), 167abb0f93cSkardel set_request_keyid }, 168abb0f93cSkardel { REQ_CONTROL_KEY, AUTH, sizeof(u_long), sizeof(u_long), 169abb0f93cSkardel set_control_keyid }, 170abb0f93cSkardel { REQ_GET_CTLSTATS, NOAUTH, 0, 0, get_ctl_stats }, 171abb0f93cSkardel #ifdef KERNEL_PLL 172abb0f93cSkardel { REQ_GET_KERNEL, NOAUTH, 0, 0, get_kernel_info }, 173abb0f93cSkardel #endif 174abb0f93cSkardel #ifdef REFCLOCK 175abb0f93cSkardel { REQ_GET_CLOCKINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), 176abb0f93cSkardel get_clock_info }, 177abb0f93cSkardel { REQ_SET_CLKFUDGE, AUTH, sizeof(struct conf_fudge), 178abb0f93cSkardel sizeof(struct conf_fudge), set_clock_fudge }, 179abb0f93cSkardel { REQ_GET_CLKBUGINFO, NOAUTH, sizeof(u_int32), sizeof(u_int32), 180abb0f93cSkardel get_clkbug_info }, 181abb0f93cSkardel #endif 182abb0f93cSkardel { REQ_IF_STATS, AUTH, 0, 0, get_if_stats }, 183abb0f93cSkardel { REQ_IF_RELOAD, AUTH, 0, 0, do_if_reload }, 184abb0f93cSkardel 185abb0f93cSkardel { NO_REQUEST, NOAUTH, 0, 0, 0 } 186abb0f93cSkardel }; 187abb0f93cSkardel 188abb0f93cSkardel 189abb0f93cSkardel /* 190abb0f93cSkardel * Authentication keyid used to authenticate requests. Zero means we 191abb0f93cSkardel * don't allow writing anything. 192abb0f93cSkardel */ 193abb0f93cSkardel keyid_t info_auth_keyid; 194abb0f93cSkardel 195abb0f93cSkardel /* 196abb0f93cSkardel * Statistic counters to keep track of requests and responses. 197abb0f93cSkardel */ 198abb0f93cSkardel u_long numrequests; /* number of requests we've received */ 199abb0f93cSkardel u_long numresppkts; /* number of resp packets sent with data */ 200abb0f93cSkardel 2012950cc38Schristos /* 2022950cc38Schristos * lazy way to count errors, indexed by the error code 2032950cc38Schristos */ 2042950cc38Schristos u_long errorcounter[MAX_INFO_ERR + 1]; 205abb0f93cSkardel 206abb0f93cSkardel /* 207abb0f93cSkardel * A hack. To keep the authentication module clear of ntp-ism's, we 208abb0f93cSkardel * include a time reset variable for its stats here. 209abb0f93cSkardel */ 2102950cc38Schristos u_long auth_timereset; 211abb0f93cSkardel 212abb0f93cSkardel /* 213abb0f93cSkardel * Response packet used by these routines. Also some state information 214abb0f93cSkardel * so that we can handle packet formatting within a common set of 215abb0f93cSkardel * subroutines. Note we try to enter data in place whenever possible, 216abb0f93cSkardel * but the need to set the more bit correctly means we occasionally 217abb0f93cSkardel * use the extra buffer and copy. 218abb0f93cSkardel */ 219abb0f93cSkardel static struct resp_pkt rpkt; 220abb0f93cSkardel static int reqver; 221abb0f93cSkardel static int seqno; 222abb0f93cSkardel static int nitems; 223abb0f93cSkardel static int itemsize; 224abb0f93cSkardel static int databytes; 225abb0f93cSkardel static char exbuf[RESP_DATA_SIZE]; 226abb0f93cSkardel static int usingexbuf; 227abb0f93cSkardel static sockaddr_u *toaddr; 2282950cc38Schristos static endpt *frominter; 229abb0f93cSkardel 230abb0f93cSkardel /* 231abb0f93cSkardel * init_request - initialize request data 232abb0f93cSkardel */ 233abb0f93cSkardel void 234abb0f93cSkardel init_request (void) 235abb0f93cSkardel { 236e19314b7Schristos size_t i; 237abb0f93cSkardel 238abb0f93cSkardel numrequests = 0; 239abb0f93cSkardel numresppkts = 0; 240abb0f93cSkardel auth_timereset = 0; 241abb0f93cSkardel info_auth_keyid = 0; /* by default, can't do this */ 242abb0f93cSkardel 243abb0f93cSkardel for (i = 0; i < sizeof(errorcounter)/sizeof(errorcounter[0]); i++) 244abb0f93cSkardel errorcounter[i] = 0; 245abb0f93cSkardel } 246abb0f93cSkardel 247abb0f93cSkardel 248abb0f93cSkardel /* 249abb0f93cSkardel * req_ack - acknowledge request with no data 250abb0f93cSkardel */ 251abb0f93cSkardel static void 252abb0f93cSkardel req_ack( 253abb0f93cSkardel sockaddr_u *srcadr, 2542950cc38Schristos endpt *inter, 255abb0f93cSkardel struct req_pkt *inpkt, 256abb0f93cSkardel int errcode 257abb0f93cSkardel ) 258abb0f93cSkardel { 259abb0f93cSkardel /* 260abb0f93cSkardel * fill in the fields 261abb0f93cSkardel */ 262abb0f93cSkardel rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); 263abb0f93cSkardel rpkt.auth_seq = AUTH_SEQ(0, 0); 264abb0f93cSkardel rpkt.implementation = inpkt->implementation; 265abb0f93cSkardel rpkt.request = inpkt->request; 266abb0f93cSkardel rpkt.err_nitems = ERR_NITEMS(errcode, 0); 267abb0f93cSkardel rpkt.mbz_itemsize = MBZ_ITEMSIZE(0); 268abb0f93cSkardel 269abb0f93cSkardel /* 270abb0f93cSkardel * send packet and bump counters 271abb0f93cSkardel */ 272abb0f93cSkardel sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE); 273abb0f93cSkardel errorcounter[errcode]++; 274abb0f93cSkardel } 275abb0f93cSkardel 276abb0f93cSkardel 277abb0f93cSkardel /* 278abb0f93cSkardel * prepare_pkt - prepare response packet for transmission, return pointer 279abb0f93cSkardel * to storage for data item. 280abb0f93cSkardel */ 2812950cc38Schristos static void * 282abb0f93cSkardel prepare_pkt( 283abb0f93cSkardel sockaddr_u *srcadr, 2842950cc38Schristos endpt *inter, 285abb0f93cSkardel struct req_pkt *pkt, 286abb0f93cSkardel size_t structsize 287abb0f93cSkardel ) 288abb0f93cSkardel { 289abb0f93cSkardel DPRINTF(4, ("request: preparing pkt\n")); 290abb0f93cSkardel 291abb0f93cSkardel /* 292abb0f93cSkardel * Fill in the implementation, request and itemsize fields 293abb0f93cSkardel * since these won't change. 294abb0f93cSkardel */ 295abb0f93cSkardel rpkt.implementation = pkt->implementation; 296abb0f93cSkardel rpkt.request = pkt->request; 297abb0f93cSkardel rpkt.mbz_itemsize = MBZ_ITEMSIZE(structsize); 298abb0f93cSkardel 299abb0f93cSkardel /* 300abb0f93cSkardel * Compute the static data needed to carry on. 301abb0f93cSkardel */ 302abb0f93cSkardel toaddr = srcadr; 303abb0f93cSkardel frominter = inter; 304abb0f93cSkardel seqno = 0; 305abb0f93cSkardel nitems = 0; 306abb0f93cSkardel itemsize = structsize; 307abb0f93cSkardel databytes = 0; 308abb0f93cSkardel usingexbuf = 0; 309abb0f93cSkardel 310abb0f93cSkardel /* 311abb0f93cSkardel * return the beginning of the packet buffer. 312abb0f93cSkardel */ 3132950cc38Schristos return &rpkt.u; 314abb0f93cSkardel } 315abb0f93cSkardel 316abb0f93cSkardel 317abb0f93cSkardel /* 318abb0f93cSkardel * more_pkt - return a data pointer for a new item. 319abb0f93cSkardel */ 3202950cc38Schristos static void * 321abb0f93cSkardel more_pkt(void) 322abb0f93cSkardel { 323abb0f93cSkardel /* 324abb0f93cSkardel * If we were using the extra buffer, send the packet. 325abb0f93cSkardel */ 326abb0f93cSkardel if (usingexbuf) { 327abb0f93cSkardel DPRINTF(3, ("request: sending pkt\n")); 328abb0f93cSkardel rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT, reqver); 329abb0f93cSkardel rpkt.auth_seq = AUTH_SEQ(0, seqno); 330abb0f93cSkardel rpkt.err_nitems = htons((u_short)nitems); 331abb0f93cSkardel sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, 332abb0f93cSkardel RESP_HEADER_SIZE + databytes); 333abb0f93cSkardel numresppkts++; 334abb0f93cSkardel 335abb0f93cSkardel /* 336abb0f93cSkardel * Copy data out of exbuf into the packet. 337abb0f93cSkardel */ 3382950cc38Schristos memcpy(&rpkt.u.data[0], exbuf, (unsigned)itemsize); 339abb0f93cSkardel seqno++; 340abb0f93cSkardel databytes = 0; 341abb0f93cSkardel nitems = 0; 342abb0f93cSkardel usingexbuf = 0; 343abb0f93cSkardel } 344abb0f93cSkardel 345abb0f93cSkardel databytes += itemsize; 346abb0f93cSkardel nitems++; 347abb0f93cSkardel if (databytes + itemsize <= RESP_DATA_SIZE) { 348abb0f93cSkardel DPRINTF(4, ("request: giving him more data\n")); 349abb0f93cSkardel /* 350abb0f93cSkardel * More room in packet. Give him the 351abb0f93cSkardel * next address. 352abb0f93cSkardel */ 3532950cc38Schristos return &rpkt.u.data[databytes]; 354abb0f93cSkardel } else { 355abb0f93cSkardel /* 356abb0f93cSkardel * No room in packet. Give him the extra 357abb0f93cSkardel * buffer unless this was the last in the sequence. 358abb0f93cSkardel */ 359abb0f93cSkardel DPRINTF(4, ("request: into extra buffer\n")); 360abb0f93cSkardel if (seqno == MAXSEQ) 361abb0f93cSkardel return NULL; 362abb0f93cSkardel else { 363abb0f93cSkardel usingexbuf = 1; 364abb0f93cSkardel return exbuf; 365abb0f93cSkardel } 366abb0f93cSkardel } 367abb0f93cSkardel } 368abb0f93cSkardel 369abb0f93cSkardel 370abb0f93cSkardel /* 371abb0f93cSkardel * flush_pkt - we're done, return remaining information. 372abb0f93cSkardel */ 373abb0f93cSkardel static void 374abb0f93cSkardel flush_pkt(void) 375abb0f93cSkardel { 376abb0f93cSkardel DPRINTF(3, ("request: flushing packet, %d items\n", nitems)); 377abb0f93cSkardel /* 378abb0f93cSkardel * Must send the last packet. If nothing in here and nothing 379abb0f93cSkardel * has been sent, send an error saying no data to be found. 380abb0f93cSkardel */ 381abb0f93cSkardel if (seqno == 0 && nitems == 0) 382abb0f93cSkardel req_ack(toaddr, frominter, (struct req_pkt *)&rpkt, 383abb0f93cSkardel INFO_ERR_NODATA); 384abb0f93cSkardel else { 385abb0f93cSkardel rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0, reqver); 386abb0f93cSkardel rpkt.auth_seq = AUTH_SEQ(0, seqno); 387abb0f93cSkardel rpkt.err_nitems = htons((u_short)nitems); 388abb0f93cSkardel sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt, 389abb0f93cSkardel RESP_HEADER_SIZE+databytes); 390abb0f93cSkardel numresppkts++; 391abb0f93cSkardel } 392abb0f93cSkardel } 393abb0f93cSkardel 394abb0f93cSkardel 395abb0f93cSkardel 396abb0f93cSkardel /* 397abb0f93cSkardel * Given a buffer, return the packet mode 398abb0f93cSkardel */ 399abb0f93cSkardel int 400abb0f93cSkardel get_packet_mode(struct recvbuf *rbufp) 401abb0f93cSkardel { 402abb0f93cSkardel struct req_pkt *inpkt = (struct req_pkt *)&rbufp->recv_pkt; 403abb0f93cSkardel return (INFO_MODE(inpkt->rm_vn_mode)); 404abb0f93cSkardel } 405abb0f93cSkardel 406abb0f93cSkardel 407abb0f93cSkardel /* 408abb0f93cSkardel * process_private - process private mode (7) packets 409abb0f93cSkardel */ 410abb0f93cSkardel void 411abb0f93cSkardel process_private( 412abb0f93cSkardel struct recvbuf *rbufp, 413abb0f93cSkardel int mod_okay 414abb0f93cSkardel ) 415abb0f93cSkardel { 41689ba794eStonnerre static u_long quiet_until; 417abb0f93cSkardel struct req_pkt *inpkt; 418abb0f93cSkardel struct req_pkt_tail *tailinpkt; 419abb0f93cSkardel sockaddr_u *srcadr; 4202950cc38Schristos endpt *inter; 4212950cc38Schristos const struct req_proc *proc; 422abb0f93cSkardel int ec; 423abb0f93cSkardel short temp_size; 424abb0f93cSkardel l_fp ftmp; 425abb0f93cSkardel double dtemp; 426abb0f93cSkardel size_t recv_len; 427abb0f93cSkardel size_t noslop_len; 428abb0f93cSkardel size_t mac_len; 429abb0f93cSkardel 430abb0f93cSkardel /* 431abb0f93cSkardel * Initialize pointers, for convenience 432abb0f93cSkardel */ 433abb0f93cSkardel recv_len = rbufp->recv_length; 434abb0f93cSkardel inpkt = (struct req_pkt *)&rbufp->recv_pkt; 435abb0f93cSkardel srcadr = &rbufp->recv_srcadr; 436abb0f93cSkardel inter = rbufp->dstadr; 437abb0f93cSkardel 438abb0f93cSkardel DPRINTF(3, ("process_private: impl %d req %d\n", 439abb0f93cSkardel inpkt->implementation, inpkt->request)); 440abb0f93cSkardel 441abb0f93cSkardel /* 442abb0f93cSkardel * Do some sanity checks on the packet. Return a format 443abb0f93cSkardel * error if it fails. 444abb0f93cSkardel */ 445abb0f93cSkardel ec = 0; 446abb0f93cSkardel if ( (++ec, ISRESPONSE(inpkt->rm_vn_mode)) 447abb0f93cSkardel || (++ec, ISMORE(inpkt->rm_vn_mode)) 448abb0f93cSkardel || (++ec, INFO_VERSION(inpkt->rm_vn_mode) > NTP_VERSION) 449abb0f93cSkardel || (++ec, INFO_VERSION(inpkt->rm_vn_mode) < NTP_OLDVERSION) 450abb0f93cSkardel || (++ec, INFO_SEQ(inpkt->auth_seq) != 0) 451abb0f93cSkardel || (++ec, INFO_ERR(inpkt->err_nitems) != 0) 452abb0f93cSkardel || (++ec, INFO_MBZ(inpkt->mbz_itemsize) != 0) 453e19314b7Schristos || (++ec, rbufp->recv_length < (int)REQ_LEN_HDR) 454abb0f93cSkardel ) { 45589ba794eStonnerre NLOG(NLOG_SYSEVENT) 45689ba794eStonnerre if (current_time >= quiet_until) { 45789ba794eStonnerre msyslog(LOG_ERR, 45889ba794eStonnerre "process_private: drop test %d" 45989ba794eStonnerre " failed, pkt from %s", 46089ba794eStonnerre ec, stoa(srcadr)); 46189ba794eStonnerre quiet_until = current_time + 60; 46289ba794eStonnerre } 463abb0f93cSkardel return; 464abb0f93cSkardel } 465abb0f93cSkardel 466abb0f93cSkardel reqver = INFO_VERSION(inpkt->rm_vn_mode); 467abb0f93cSkardel 468abb0f93cSkardel /* 469abb0f93cSkardel * Get the appropriate procedure list to search. 470abb0f93cSkardel */ 471abb0f93cSkardel if (inpkt->implementation == IMPL_UNIV) 472abb0f93cSkardel proc = univ_codes; 473abb0f93cSkardel else if ((inpkt->implementation == IMPL_XNTPD) || 474abb0f93cSkardel (inpkt->implementation == IMPL_XNTPD_OLD)) 475abb0f93cSkardel proc = ntp_codes; 476abb0f93cSkardel else { 477abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_IMPL); 478abb0f93cSkardel return; 479abb0f93cSkardel } 480abb0f93cSkardel 481abb0f93cSkardel /* 482abb0f93cSkardel * Search the list for the request codes. If it isn't one 483abb0f93cSkardel * we know, return an error. 484abb0f93cSkardel */ 485abb0f93cSkardel while (proc->request_code != NO_REQUEST) { 486abb0f93cSkardel if (proc->request_code == (short) inpkt->request) 487abb0f93cSkardel break; 488abb0f93cSkardel proc++; 489abb0f93cSkardel } 490abb0f93cSkardel if (proc->request_code == NO_REQUEST) { 491abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_REQ); 492abb0f93cSkardel return; 493abb0f93cSkardel } 494abb0f93cSkardel 495abb0f93cSkardel DPRINTF(4, ("found request in tables\n")); 496abb0f93cSkardel 497abb0f93cSkardel /* 498abb0f93cSkardel * If we need data, check to see if we have some. If we 499abb0f93cSkardel * don't, check to see that there is none (picky, picky). 500abb0f93cSkardel */ 501abb0f93cSkardel 502abb0f93cSkardel /* This part is a bit tricky, we want to be sure that the size 503abb0f93cSkardel * returned is either the old or the new size. We also can find 504abb0f93cSkardel * out if the client can accept both types of messages this way. 505abb0f93cSkardel * 506abb0f93cSkardel * Handle the exception of REQ_CONFIG. It can have two data sizes. 507abb0f93cSkardel */ 508abb0f93cSkardel temp_size = INFO_ITEMSIZE(inpkt->mbz_itemsize); 509abb0f93cSkardel if ((temp_size != proc->sizeofitem && 510abb0f93cSkardel temp_size != proc->v6_sizeofitem) && 511abb0f93cSkardel !(inpkt->implementation == IMPL_XNTPD && 512abb0f93cSkardel inpkt->request == REQ_CONFIG && 513abb0f93cSkardel temp_size == sizeof(struct old_conf_peer))) { 514abb0f93cSkardel DPRINTF(3, ("process_private: wrong item size, received %d, should be %d or %d\n", 515abb0f93cSkardel temp_size, proc->sizeofitem, proc->v6_sizeofitem)); 516abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 517abb0f93cSkardel return; 518abb0f93cSkardel } 519abb0f93cSkardel if ((proc->sizeofitem != 0) && 520abb0f93cSkardel ((size_t)(temp_size * INFO_NITEMS(inpkt->err_nitems)) > 521abb0f93cSkardel (recv_len - REQ_LEN_HDR))) { 522abb0f93cSkardel DPRINTF(3, ("process_private: not enough data\n")); 523abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 524abb0f93cSkardel return; 525abb0f93cSkardel } 526abb0f93cSkardel 527abb0f93cSkardel switch (inpkt->implementation) { 528abb0f93cSkardel case IMPL_XNTPD: 529abb0f93cSkardel client_v6_capable = 1; 530abb0f93cSkardel break; 531abb0f93cSkardel case IMPL_XNTPD_OLD: 532abb0f93cSkardel client_v6_capable = 0; 533abb0f93cSkardel break; 534abb0f93cSkardel default: 535abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 536abb0f93cSkardel return; 537abb0f93cSkardel } 538abb0f93cSkardel 539abb0f93cSkardel /* 540abb0f93cSkardel * If we need to authenticate, do so. Note that an 541abb0f93cSkardel * authenticatable packet must include a mac field, must 542abb0f93cSkardel * have used key info_auth_keyid and must have included 543abb0f93cSkardel * a time stamp in the appropriate field. The time stamp 544abb0f93cSkardel * must be within INFO_TS_MAXSKEW of the receive 545abb0f93cSkardel * time stamp. 546abb0f93cSkardel */ 547abb0f93cSkardel if (proc->needs_auth && sys_authenticate) { 548abb0f93cSkardel 549abb0f93cSkardel if (recv_len < (REQ_LEN_HDR + 550abb0f93cSkardel (INFO_ITEMSIZE(inpkt->mbz_itemsize) * 551abb0f93cSkardel INFO_NITEMS(inpkt->err_nitems)) + 552abb0f93cSkardel REQ_TAIL_MIN)) { 553abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 554abb0f93cSkardel return; 555abb0f93cSkardel } 556abb0f93cSkardel 557abb0f93cSkardel /* 558abb0f93cSkardel * For 16-octet digests, regardless of itemsize and 559abb0f93cSkardel * nitems, authenticated requests are a fixed size 560abb0f93cSkardel * with the timestamp, key ID, and digest located 561abb0f93cSkardel * at the end of the packet. Because the key ID 562abb0f93cSkardel * determining the digest size precedes the digest, 563abb0f93cSkardel * for larger digests the fixed size request scheme 564abb0f93cSkardel * is abandoned and the timestamp, key ID, and digest 565abb0f93cSkardel * are located relative to the start of the packet, 566abb0f93cSkardel * with the digest size determined by the packet size. 567abb0f93cSkardel */ 568abb0f93cSkardel noslop_len = REQ_LEN_HDR 569abb0f93cSkardel + INFO_ITEMSIZE(inpkt->mbz_itemsize) * 570abb0f93cSkardel INFO_NITEMS(inpkt->err_nitems) 571abb0f93cSkardel + sizeof(inpkt->tstamp); 572abb0f93cSkardel /* 32-bit alignment */ 573abb0f93cSkardel noslop_len = (noslop_len + 3) & ~3; 574abb0f93cSkardel if (recv_len > (noslop_len + MAX_MAC_LEN)) 575abb0f93cSkardel mac_len = 20; 576abb0f93cSkardel else 577abb0f93cSkardel mac_len = recv_len - noslop_len; 578abb0f93cSkardel 579abb0f93cSkardel tailinpkt = (void *)((char *)inpkt + recv_len - 580abb0f93cSkardel (mac_len + sizeof(inpkt->tstamp))); 581abb0f93cSkardel 582abb0f93cSkardel /* 583abb0f93cSkardel * If this guy is restricted from doing this, don't let 584abb0f93cSkardel * him. If the wrong key was used, or packet doesn't 585abb0f93cSkardel * have mac, return. 586abb0f93cSkardel */ 5874eea345dSchristos /* XXX: Use authistrustedip(), or equivalent. */ 588abb0f93cSkardel if (!INFO_IS_AUTH(inpkt->auth_seq) || !info_auth_keyid 589abb0f93cSkardel || ntohl(tailinpkt->keyid) != info_auth_keyid) { 5902f3ccb49Skardel DPRINTF(5, ("failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n", 591abb0f93cSkardel INFO_IS_AUTH(inpkt->auth_seq), 592abb0f93cSkardel info_auth_keyid, 5933123f114Skardel ntohl(tailinpkt->keyid), (u_long)mac_len)); 594abb0f93cSkardel #ifdef DEBUG 595abb0f93cSkardel msyslog(LOG_DEBUG, 5962f3ccb49Skardel "process_private: failed auth %d info_auth_keyid %u pkt keyid %u maclen %lu\n", 597abb0f93cSkardel INFO_IS_AUTH(inpkt->auth_seq), 598abb0f93cSkardel info_auth_keyid, 5993123f114Skardel ntohl(tailinpkt->keyid), (u_long)mac_len); 600abb0f93cSkardel #endif 601abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); 602abb0f93cSkardel return; 603abb0f93cSkardel } 604abb0f93cSkardel if (recv_len > REQ_LEN_NOMAC + MAX_MAC_LEN) { 605e19314b7Schristos DPRINTF(5, ("bad pkt length %zu\n", recv_len)); 606abb0f93cSkardel msyslog(LOG_ERR, 607e19314b7Schristos "process_private: bad pkt length %zu", 608abb0f93cSkardel recv_len); 609abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 610abb0f93cSkardel return; 611abb0f93cSkardel } 612abb0f93cSkardel if (!mod_okay || !authhavekey(info_auth_keyid)) { 613abb0f93cSkardel DPRINTF(5, ("failed auth mod_okay %d\n", 614abb0f93cSkardel mod_okay)); 615abb0f93cSkardel #ifdef DEBUG 616abb0f93cSkardel msyslog(LOG_DEBUG, 617abb0f93cSkardel "process_private: failed auth mod_okay %d\n", 618abb0f93cSkardel mod_okay); 619abb0f93cSkardel #endif 6202950cc38Schristos if (!mod_okay) { 6212950cc38Schristos sys_restricted++; 6222950cc38Schristos } 623abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); 624abb0f93cSkardel return; 625abb0f93cSkardel } 626abb0f93cSkardel 627abb0f93cSkardel /* 628abb0f93cSkardel * calculate absolute time difference between xmit time stamp 629abb0f93cSkardel * and receive time stamp. If too large, too bad. 630abb0f93cSkardel */ 631abb0f93cSkardel NTOHL_FP(&tailinpkt->tstamp, &ftmp); 632abb0f93cSkardel L_SUB(&ftmp, &rbufp->recv_time); 633abb0f93cSkardel LFPTOD(&ftmp, dtemp); 634abb0f93cSkardel if (fabs(dtemp) > INFO_TS_MAXSKEW) { 635abb0f93cSkardel /* 636abb0f93cSkardel * He's a loser. Tell him. 637abb0f93cSkardel */ 638abb0f93cSkardel DPRINTF(5, ("xmit/rcv timestamp delta %g > INFO_TS_MAXSKEW %g\n", 639abb0f93cSkardel dtemp, INFO_TS_MAXSKEW)); 640abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); 641abb0f93cSkardel return; 642abb0f93cSkardel } 643abb0f93cSkardel 644abb0f93cSkardel /* 645abb0f93cSkardel * So far so good. See if decryption works out okay. 646abb0f93cSkardel */ 647abb0f93cSkardel if (!authdecrypt(info_auth_keyid, (u_int32 *)inpkt, 648abb0f93cSkardel recv_len - mac_len, mac_len)) { 649abb0f93cSkardel DPRINTF(5, ("authdecrypt failed\n")); 650abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_AUTH); 651abb0f93cSkardel return; 652abb0f93cSkardel } 653abb0f93cSkardel } 654abb0f93cSkardel 655abb0f93cSkardel DPRINTF(3, ("process_private: all okay, into handler\n")); 656abb0f93cSkardel /* 657abb0f93cSkardel * Packet is okay. Call the handler to send him data. 658abb0f93cSkardel */ 659abb0f93cSkardel (proc->handler)(srcadr, inter, inpkt); 660abb0f93cSkardel } 661abb0f93cSkardel 662abb0f93cSkardel 663abb0f93cSkardel /* 6642950cc38Schristos * list_peers - send a list of the peers 665abb0f93cSkardel */ 666abb0f93cSkardel static void 6672950cc38Schristos list_peers( 668abb0f93cSkardel sockaddr_u *srcadr, 6692950cc38Schristos endpt *inter, 670abb0f93cSkardel struct req_pkt *inpkt 671abb0f93cSkardel ) 672abb0f93cSkardel { 6732950cc38Schristos struct info_peer_list * ip; 67468dbbb44Schristos const struct peer * pp; 675abb0f93cSkardel 676abb0f93cSkardel ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt, 677abb0f93cSkardel v6sizeof(struct info_peer_list)); 6782950cc38Schristos for (pp = peer_list; pp != NULL && ip != NULL; pp = pp->p_link) { 679abb0f93cSkardel if (IS_IPV6(&pp->srcadr)) { 68068dbbb44Schristos if (!client_v6_capable) 68168dbbb44Schristos continue; 682abb0f93cSkardel ip->addr6 = SOCK_ADDR6(&pp->srcadr); 683abb0f93cSkardel ip->v6_flag = 1; 684abb0f93cSkardel } else { 685abb0f93cSkardel ip->addr = NSRCADR(&pp->srcadr); 686abb0f93cSkardel if (client_v6_capable) 687abb0f93cSkardel ip->v6_flag = 0; 688abb0f93cSkardel } 689abb0f93cSkardel 690abb0f93cSkardel ip->port = NSRCPORT(&pp->srcadr); 691abb0f93cSkardel ip->hmode = pp->hmode; 692abb0f93cSkardel ip->flags = 0; 693abb0f93cSkardel if (pp->flags & FLAG_CONFIG) 694abb0f93cSkardel ip->flags |= INFO_FLAG_CONFIG; 695abb0f93cSkardel if (pp == sys_peer) 696abb0f93cSkardel ip->flags |= INFO_FLAG_SYSPEER; 697abb0f93cSkardel if (pp->status == CTL_PST_SEL_SYNCCAND) 698abb0f93cSkardel ip->flags |= INFO_FLAG_SEL_CANDIDATE; 699abb0f93cSkardel if (pp->status >= CTL_PST_SEL_SYSPEER) 700abb0f93cSkardel ip->flags |= INFO_FLAG_SHORTLIST; 701abb0f93cSkardel ip = (struct info_peer_list *)more_pkt(); 7022950cc38Schristos } /* for pp */ 7032950cc38Schristos 704abb0f93cSkardel flush_pkt(); 705abb0f93cSkardel } 706abb0f93cSkardel 707abb0f93cSkardel 708abb0f93cSkardel /* 7092950cc38Schristos * list_peers_sum - return extended peer list 710abb0f93cSkardel */ 711abb0f93cSkardel static void 7122950cc38Schristos list_peers_sum( 713abb0f93cSkardel sockaddr_u *srcadr, 7142950cc38Schristos endpt *inter, 715abb0f93cSkardel struct req_pkt *inpkt 716abb0f93cSkardel ) 717abb0f93cSkardel { 71868dbbb44Schristos struct info_peer_summary * ips; 71968dbbb44Schristos const struct peer * pp; 720abb0f93cSkardel l_fp ltmp; 721abb0f93cSkardel 7222950cc38Schristos DPRINTF(3, ("wants peer list summary\n")); 7232950cc38Schristos 724abb0f93cSkardel ips = (struct info_peer_summary *)prepare_pkt(srcadr, inter, inpkt, 725abb0f93cSkardel v6sizeof(struct info_peer_summary)); 7262950cc38Schristos for (pp = peer_list; pp != NULL && ips != NULL; pp = pp->p_link) { 7272950cc38Schristos DPRINTF(4, ("sum: got one\n")); 728abb0f93cSkardel /* 729abb0f93cSkardel * Be careful here not to return v6 peers when we 730abb0f93cSkardel * want only v4. 731abb0f93cSkardel */ 732abb0f93cSkardel if (IS_IPV6(&pp->srcadr)) { 73368dbbb44Schristos if (!client_v6_capable) 73468dbbb44Schristos continue; 735abb0f93cSkardel ips->srcadr6 = SOCK_ADDR6(&pp->srcadr); 736abb0f93cSkardel ips->v6_flag = 1; 737abb0f93cSkardel if (pp->dstadr) 738abb0f93cSkardel ips->dstadr6 = SOCK_ADDR6(&pp->dstadr->sin); 739abb0f93cSkardel else 7402950cc38Schristos ZERO(ips->dstadr6); 741abb0f93cSkardel } else { 742abb0f93cSkardel ips->srcadr = NSRCADR(&pp->srcadr); 743abb0f93cSkardel if (client_v6_capable) 744abb0f93cSkardel ips->v6_flag = 0; 745abb0f93cSkardel 746abb0f93cSkardel if (pp->dstadr) { 747abb0f93cSkardel if (!pp->processed) 748abb0f93cSkardel ips->dstadr = NSRCADR(&pp->dstadr->sin); 749abb0f93cSkardel else { 750abb0f93cSkardel if (MDF_BCAST == pp->cast_flags) 751abb0f93cSkardel ips->dstadr = NSRCADR(&pp->dstadr->bcast); 752abb0f93cSkardel else if (pp->cast_flags) { 753abb0f93cSkardel ips->dstadr = NSRCADR(&pp->dstadr->sin); 754abb0f93cSkardel if (!ips->dstadr) 755abb0f93cSkardel ips->dstadr = NSRCADR(&pp->dstadr->bcast); 756abb0f93cSkardel } 757abb0f93cSkardel } 75868dbbb44Schristos } else { 759abb0f93cSkardel ips->dstadr = 0; 76068dbbb44Schristos } 761abb0f93cSkardel } 762abb0f93cSkardel 763abb0f93cSkardel ips->srcport = NSRCPORT(&pp->srcadr); 764abb0f93cSkardel ips->stratum = pp->stratum; 765abb0f93cSkardel ips->hpoll = pp->hpoll; 766abb0f93cSkardel ips->ppoll = pp->ppoll; 767abb0f93cSkardel ips->reach = pp->reach; 768abb0f93cSkardel ips->flags = 0; 769abb0f93cSkardel if (pp == sys_peer) 770abb0f93cSkardel ips->flags |= INFO_FLAG_SYSPEER; 771abb0f93cSkardel if (pp->flags & FLAG_CONFIG) 772abb0f93cSkardel ips->flags |= INFO_FLAG_CONFIG; 773abb0f93cSkardel if (pp->flags & FLAG_REFCLOCK) 774abb0f93cSkardel ips->flags |= INFO_FLAG_REFCLOCK; 775abb0f93cSkardel if (pp->flags & FLAG_PREFER) 776abb0f93cSkardel ips->flags |= INFO_FLAG_PREFER; 777abb0f93cSkardel if (pp->flags & FLAG_BURST) 778abb0f93cSkardel ips->flags |= INFO_FLAG_BURST; 779abb0f93cSkardel if (pp->status == CTL_PST_SEL_SYNCCAND) 780abb0f93cSkardel ips->flags |= INFO_FLAG_SEL_CANDIDATE; 781abb0f93cSkardel if (pp->status >= CTL_PST_SEL_SYSPEER) 782abb0f93cSkardel ips->flags |= INFO_FLAG_SHORTLIST; 783abb0f93cSkardel ips->hmode = pp->hmode; 784abb0f93cSkardel ips->delay = HTONS_FP(DTOFP(pp->delay)); 785abb0f93cSkardel DTOLFP(pp->offset, <mp); 786abb0f93cSkardel HTONL_FP(<mp, &ips->offset); 787abb0f93cSkardel ips->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp))); 78868dbbb44Schristos 789abb0f93cSkardel ips = (struct info_peer_summary *)more_pkt(); 7902950cc38Schristos } /* for pp */ 7912950cc38Schristos 792abb0f93cSkardel flush_pkt(); 793abb0f93cSkardel } 794abb0f93cSkardel 795abb0f93cSkardel 796abb0f93cSkardel /* 797abb0f93cSkardel * peer_info - send information for one or more peers 798abb0f93cSkardel */ 799abb0f93cSkardel static void 800abb0f93cSkardel peer_info ( 801abb0f93cSkardel sockaddr_u *srcadr, 8022950cc38Schristos endpt *inter, 803abb0f93cSkardel struct req_pkt *inpkt 804abb0f93cSkardel ) 805abb0f93cSkardel { 8062950cc38Schristos u_short items; 8072950cc38Schristos size_t item_sz; 8082950cc38Schristos char * datap; 8092950cc38Schristos struct info_peer_list ipl; 8102950cc38Schristos struct peer * pp; 8112950cc38Schristos struct info_peer * ip; 8122950cc38Schristos int i; 8132950cc38Schristos int j; 814abb0f93cSkardel sockaddr_u addr; 815abb0f93cSkardel l_fp ltmp; 816abb0f93cSkardel 817abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 8182950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 8192950cc38Schristos datap = inpkt->u.data; 8202950cc38Schristos if (item_sz != sizeof(ipl)) { 8212950cc38Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 8222950cc38Schristos return; 8232950cc38Schristos } 8242950cc38Schristos ip = prepare_pkt(srcadr, inter, inpkt, 825abb0f93cSkardel v6sizeof(struct info_peer)); 8262950cc38Schristos while (items-- > 0 && ip != NULL) { 8272950cc38Schristos ZERO(ipl); 8282950cc38Schristos memcpy(&ipl, datap, item_sz); 829abb0f93cSkardel ZERO_SOCK(&addr); 8302950cc38Schristos NSRCPORT(&addr) = ipl.port; 8312950cc38Schristos if (client_v6_capable && ipl.v6_flag) { 832abb0f93cSkardel AF(&addr) = AF_INET6; 8332950cc38Schristos SOCK_ADDR6(&addr) = ipl.addr6; 834abb0f93cSkardel } else { 835abb0f93cSkardel AF(&addr) = AF_INET; 8362950cc38Schristos NSRCADR(&addr) = ipl.addr; 837abb0f93cSkardel } 838abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 8393123f114Skardel addr.sa.sa_len = SOCKLEN(&addr); 840abb0f93cSkardel #endif 8412950cc38Schristos datap += item_sz; 8422950cc38Schristos 8434eea345dSchristos pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL); 8443123f114Skardel if (NULL == pp) 845abb0f93cSkardel continue; 846cdfa2a7eSchristos if (IS_IPV6(&pp->srcadr)) { 847abb0f93cSkardel if (pp->dstadr) 848abb0f93cSkardel ip->dstadr6 = 849abb0f93cSkardel (MDF_BCAST == pp->cast_flags) 850abb0f93cSkardel ? SOCK_ADDR6(&pp->dstadr->bcast) 851abb0f93cSkardel : SOCK_ADDR6(&pp->dstadr->sin); 852abb0f93cSkardel else 8532950cc38Schristos ZERO(ip->dstadr6); 854abb0f93cSkardel 855abb0f93cSkardel ip->srcadr6 = SOCK_ADDR6(&pp->srcadr); 856abb0f93cSkardel ip->v6_flag = 1; 857abb0f93cSkardel } else { 858abb0f93cSkardel if (pp->dstadr) { 859abb0f93cSkardel if (!pp->processed) 860abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->sin); 861abb0f93cSkardel else { 862abb0f93cSkardel if (MDF_BCAST == pp->cast_flags) 863abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->bcast); 864abb0f93cSkardel else if (pp->cast_flags) { 865abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->sin); 866abb0f93cSkardel if (!ip->dstadr) 867abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->bcast); 868abb0f93cSkardel } 869abb0f93cSkardel } 870abb0f93cSkardel } else 871abb0f93cSkardel ip->dstadr = 0; 872abb0f93cSkardel 873abb0f93cSkardel ip->srcadr = NSRCADR(&pp->srcadr); 874abb0f93cSkardel if (client_v6_capable) 875abb0f93cSkardel ip->v6_flag = 0; 876abb0f93cSkardel } 877abb0f93cSkardel ip->srcport = NSRCPORT(&pp->srcadr); 878abb0f93cSkardel ip->flags = 0; 879abb0f93cSkardel if (pp == sys_peer) 880abb0f93cSkardel ip->flags |= INFO_FLAG_SYSPEER; 881abb0f93cSkardel if (pp->flags & FLAG_CONFIG) 882abb0f93cSkardel ip->flags |= INFO_FLAG_CONFIG; 883abb0f93cSkardel if (pp->flags & FLAG_REFCLOCK) 884abb0f93cSkardel ip->flags |= INFO_FLAG_REFCLOCK; 885abb0f93cSkardel if (pp->flags & FLAG_PREFER) 886abb0f93cSkardel ip->flags |= INFO_FLAG_PREFER; 887abb0f93cSkardel if (pp->flags & FLAG_BURST) 888abb0f93cSkardel ip->flags |= INFO_FLAG_BURST; 889abb0f93cSkardel if (pp->status == CTL_PST_SEL_SYNCCAND) 890abb0f93cSkardel ip->flags |= INFO_FLAG_SEL_CANDIDATE; 891abb0f93cSkardel if (pp->status >= CTL_PST_SEL_SYSPEER) 892abb0f93cSkardel ip->flags |= INFO_FLAG_SHORTLIST; 893abb0f93cSkardel ip->leap = pp->leap; 894abb0f93cSkardel ip->hmode = pp->hmode; 89579045f13Schristos ip->pmode = pp->pmode; 896abb0f93cSkardel ip->keyid = pp->keyid; 897abb0f93cSkardel ip->stratum = pp->stratum; 898abb0f93cSkardel ip->ppoll = pp->ppoll; 899abb0f93cSkardel ip->hpoll = pp->hpoll; 900abb0f93cSkardel ip->precision = pp->precision; 901abb0f93cSkardel ip->version = pp->version; 902abb0f93cSkardel ip->reach = pp->reach; 903abb0f93cSkardel ip->unreach = (u_char)pp->unreach; 904abb0f93cSkardel ip->flash = (u_char)pp->flash; 905abb0f93cSkardel ip->flash2 = (u_short)pp->flash; 906abb0f93cSkardel ip->estbdelay = HTONS_FP(DTOFP(pp->delay)); 9072950cc38Schristos ip->ttl = (u_char)pp->ttl; 908abb0f93cSkardel ip->associd = htons(pp->associd); 909abb0f93cSkardel ip->rootdelay = HTONS_FP(DTOUFP(pp->rootdelay)); 910abb0f93cSkardel ip->rootdispersion = HTONS_FP(DTOUFP(pp->rootdisp)); 911abb0f93cSkardel ip->refid = pp->refid; 912abb0f93cSkardel HTONL_FP(&pp->reftime, &ip->reftime); 913abb0f93cSkardel HTONL_FP(&pp->aorg, &ip->org); 914abb0f93cSkardel HTONL_FP(&pp->rec, &ip->rec); 915abb0f93cSkardel HTONL_FP(&pp->xmt, &ip->xmt); 916abb0f93cSkardel j = pp->filter_nextpt - 1; 917abb0f93cSkardel for (i = 0; i < NTP_SHIFT; i++, j--) { 918abb0f93cSkardel if (j < 0) 919abb0f93cSkardel j = NTP_SHIFT-1; 920abb0f93cSkardel ip->filtdelay[i] = HTONS_FP(DTOFP(pp->filter_delay[j])); 921abb0f93cSkardel DTOLFP(pp->filter_offset[j], <mp); 922abb0f93cSkardel HTONL_FP(<mp, &ip->filtoffset[i]); 9232950cc38Schristos ip->order[i] = (u_char)((pp->filter_nextpt + 9242950cc38Schristos NTP_SHIFT - 1) - 9252950cc38Schristos pp->filter_order[i]); 926abb0f93cSkardel if (ip->order[i] >= NTP_SHIFT) 927abb0f93cSkardel ip->order[i] -= NTP_SHIFT; 928abb0f93cSkardel } 929abb0f93cSkardel DTOLFP(pp->offset, <mp); 930abb0f93cSkardel HTONL_FP(<mp, &ip->offset); 931abb0f93cSkardel ip->delay = HTONS_FP(DTOFP(pp->delay)); 932abb0f93cSkardel ip->dispersion = HTONS_FP(DTOUFP(SQRT(pp->disp))); 933abb0f93cSkardel ip->selectdisp = HTONS_FP(DTOUFP(SQRT(pp->jitter))); 9342950cc38Schristos ip = more_pkt(); 935abb0f93cSkardel } 936abb0f93cSkardel flush_pkt(); 937abb0f93cSkardel } 938abb0f93cSkardel 939abb0f93cSkardel 940abb0f93cSkardel /* 941abb0f93cSkardel * peer_stats - send statistics for one or more peers 942abb0f93cSkardel */ 943abb0f93cSkardel static void 944abb0f93cSkardel peer_stats ( 945abb0f93cSkardel sockaddr_u *srcadr, 9462950cc38Schristos endpt *inter, 947abb0f93cSkardel struct req_pkt *inpkt 948abb0f93cSkardel ) 949abb0f93cSkardel { 9502950cc38Schristos u_short items; 9512950cc38Schristos size_t item_sz; 9522950cc38Schristos char * datap; 9532950cc38Schristos struct info_peer_list ipl; 9542950cc38Schristos struct peer * pp; 9552950cc38Schristos struct info_peer_stats *ip; 956abb0f93cSkardel sockaddr_u addr; 957abb0f93cSkardel 9582950cc38Schristos DPRINTF(1, ("peer_stats: called\n")); 959abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 9602950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 9612950cc38Schristos datap = inpkt->u.data; 9622950cc38Schristos if (item_sz > sizeof(ipl)) { 9632950cc38Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 9642950cc38Schristos return; 9652950cc38Schristos } 9662950cc38Schristos ip = prepare_pkt(srcadr, inter, inpkt, 967abb0f93cSkardel v6sizeof(struct info_peer_stats)); 9682950cc38Schristos while (items-- > 0 && ip != NULL) { 9692950cc38Schristos ZERO(ipl); 9702950cc38Schristos memcpy(&ipl, datap, item_sz); 9712950cc38Schristos ZERO(addr); 9722950cc38Schristos NSRCPORT(&addr) = ipl.port; 9732950cc38Schristos if (client_v6_capable && ipl.v6_flag) { 974abb0f93cSkardel AF(&addr) = AF_INET6; 9752950cc38Schristos SOCK_ADDR6(&addr) = ipl.addr6; 976abb0f93cSkardel } else { 977abb0f93cSkardel AF(&addr) = AF_INET; 9782950cc38Schristos NSRCADR(&addr) = ipl.addr; 979abb0f93cSkardel } 980abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 9813123f114Skardel addr.sa.sa_len = SOCKLEN(&addr); 982abb0f93cSkardel #endif 983abb0f93cSkardel DPRINTF(1, ("peer_stats: looking for %s, %d, %d\n", 9842950cc38Schristos stoa(&addr), ipl.port, NSRCPORT(&addr))); 985abb0f93cSkardel 9862950cc38Schristos datap += item_sz; 987abb0f93cSkardel 9884eea345dSchristos pp = findexistingpeer(&addr, NULL, NULL, -1, 0, NULL); 9893123f114Skardel if (NULL == pp) 990abb0f93cSkardel continue; 991abb0f93cSkardel 992abb0f93cSkardel DPRINTF(1, ("peer_stats: found %s\n", stoa(&addr))); 993abb0f93cSkardel 994abb0f93cSkardel if (IS_IPV4(&pp->srcadr)) { 995abb0f93cSkardel if (pp->dstadr) { 996abb0f93cSkardel if (!pp->processed) 997abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->sin); 998abb0f93cSkardel else { 999abb0f93cSkardel if (MDF_BCAST == pp->cast_flags) 1000abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->bcast); 1001abb0f93cSkardel else if (pp->cast_flags) { 1002abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->sin); 1003abb0f93cSkardel if (!ip->dstadr) 1004abb0f93cSkardel ip->dstadr = NSRCADR(&pp->dstadr->bcast); 1005abb0f93cSkardel } 1006abb0f93cSkardel } 1007abb0f93cSkardel } else 1008abb0f93cSkardel ip->dstadr = 0; 1009abb0f93cSkardel 1010abb0f93cSkardel ip->srcadr = NSRCADR(&pp->srcadr); 1011abb0f93cSkardel if (client_v6_capable) 1012abb0f93cSkardel ip->v6_flag = 0; 1013abb0f93cSkardel } else { 1014abb0f93cSkardel if (pp->dstadr) 1015abb0f93cSkardel ip->dstadr6 = 1016abb0f93cSkardel (MDF_BCAST == pp->cast_flags) 1017abb0f93cSkardel ? SOCK_ADDR6(&pp->dstadr->bcast) 1018abb0f93cSkardel : SOCK_ADDR6(&pp->dstadr->sin); 1019abb0f93cSkardel else 10202950cc38Schristos ZERO(ip->dstadr6); 1021abb0f93cSkardel 1022abb0f93cSkardel ip->srcadr6 = SOCK_ADDR6(&pp->srcadr); 1023abb0f93cSkardel ip->v6_flag = 1; 1024abb0f93cSkardel } 1025abb0f93cSkardel ip->srcport = NSRCPORT(&pp->srcadr); 1026abb0f93cSkardel ip->flags = 0; 1027abb0f93cSkardel if (pp == sys_peer) 1028abb0f93cSkardel ip->flags |= INFO_FLAG_SYSPEER; 1029abb0f93cSkardel if (pp->flags & FLAG_CONFIG) 1030abb0f93cSkardel ip->flags |= INFO_FLAG_CONFIG; 1031abb0f93cSkardel if (pp->flags & FLAG_REFCLOCK) 1032abb0f93cSkardel ip->flags |= INFO_FLAG_REFCLOCK; 1033abb0f93cSkardel if (pp->flags & FLAG_PREFER) 1034abb0f93cSkardel ip->flags |= INFO_FLAG_PREFER; 1035abb0f93cSkardel if (pp->flags & FLAG_BURST) 1036abb0f93cSkardel ip->flags |= INFO_FLAG_BURST; 1037abb0f93cSkardel if (pp->flags & FLAG_IBURST) 1038abb0f93cSkardel ip->flags |= INFO_FLAG_IBURST; 1039abb0f93cSkardel if (pp->status == CTL_PST_SEL_SYNCCAND) 1040abb0f93cSkardel ip->flags |= INFO_FLAG_SEL_CANDIDATE; 1041abb0f93cSkardel if (pp->status >= CTL_PST_SEL_SYSPEER) 1042abb0f93cSkardel ip->flags |= INFO_FLAG_SHORTLIST; 1043abb0f93cSkardel ip->flags = htons(ip->flags); 1044abb0f93cSkardel ip->timereceived = htonl((u_int32)(current_time - pp->timereceived)); 1045abb0f93cSkardel ip->timetosend = htonl(pp->nextdate - current_time); 1046abb0f93cSkardel ip->timereachable = htonl((u_int32)(current_time - pp->timereachable)); 1047abb0f93cSkardel ip->sent = htonl((u_int32)(pp->sent)); 1048abb0f93cSkardel ip->processed = htonl((u_int32)(pp->processed)); 1049abb0f93cSkardel ip->badauth = htonl((u_int32)(pp->badauth)); 1050abb0f93cSkardel ip->bogusorg = htonl((u_int32)(pp->bogusorg)); 1051abb0f93cSkardel ip->oldpkt = htonl((u_int32)(pp->oldpkt)); 1052abb0f93cSkardel ip->seldisp = htonl((u_int32)(pp->seldisptoolarge)); 1053abb0f93cSkardel ip->selbroken = htonl((u_int32)(pp->selbroken)); 1054abb0f93cSkardel ip->candidate = pp->status; 1055abb0f93cSkardel ip = (struct info_peer_stats *)more_pkt(); 1056abb0f93cSkardel } 1057abb0f93cSkardel flush_pkt(); 1058abb0f93cSkardel } 1059abb0f93cSkardel 1060abb0f93cSkardel 1061abb0f93cSkardel /* 1062abb0f93cSkardel * sys_info - return system info 1063abb0f93cSkardel */ 1064abb0f93cSkardel static void 1065abb0f93cSkardel sys_info( 1066abb0f93cSkardel sockaddr_u *srcadr, 10672950cc38Schristos endpt *inter, 1068abb0f93cSkardel struct req_pkt *inpkt 1069abb0f93cSkardel ) 1070abb0f93cSkardel { 1071abb0f93cSkardel register struct info_sys *is; 1072abb0f93cSkardel 1073abb0f93cSkardel is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt, 1074abb0f93cSkardel v6sizeof(struct info_sys)); 1075abb0f93cSkardel 1076abb0f93cSkardel if (sys_peer) { 1077abb0f93cSkardel if (IS_IPV4(&sys_peer->srcadr)) { 1078abb0f93cSkardel is->peer = NSRCADR(&sys_peer->srcadr); 1079abb0f93cSkardel if (client_v6_capable) 1080abb0f93cSkardel is->v6_flag = 0; 1081abb0f93cSkardel } else if (client_v6_capable) { 1082abb0f93cSkardel is->peer6 = SOCK_ADDR6(&sys_peer->srcadr); 1083abb0f93cSkardel is->v6_flag = 1; 1084abb0f93cSkardel } 1085abb0f93cSkardel is->peer_mode = sys_peer->hmode; 1086abb0f93cSkardel } else { 1087abb0f93cSkardel is->peer = 0; 1088abb0f93cSkardel if (client_v6_capable) { 1089abb0f93cSkardel is->v6_flag = 0; 1090abb0f93cSkardel } 1091abb0f93cSkardel is->peer_mode = 0; 1092abb0f93cSkardel } 1093abb0f93cSkardel 1094abb0f93cSkardel is->leap = sys_leap; 1095abb0f93cSkardel is->stratum = sys_stratum; 1096abb0f93cSkardel is->precision = sys_precision; 1097abb0f93cSkardel is->rootdelay = htonl(DTOFP(sys_rootdelay)); 1098abb0f93cSkardel is->rootdispersion = htonl(DTOUFP(sys_rootdisp)); 1099abb0f93cSkardel is->frequency = htonl(DTOFP(sys_jitter)); 11002950cc38Schristos is->stability = htonl(DTOUFP(clock_stability * 1e6)); 1101abb0f93cSkardel is->refid = sys_refid; 1102abb0f93cSkardel HTONL_FP(&sys_reftime, &is->reftime); 1103abb0f93cSkardel 1104abb0f93cSkardel is->poll = sys_poll; 1105abb0f93cSkardel 1106abb0f93cSkardel is->flags = 0; 1107abb0f93cSkardel if (sys_authenticate) 1108abb0f93cSkardel is->flags |= INFO_FLAG_AUTHENTICATE; 1109eabc0478Schristos if (sys_bclient || sys_mclient) 1110abb0f93cSkardel is->flags |= INFO_FLAG_BCLIENT; 1111abb0f93cSkardel #ifdef REFCLOCK 1112abb0f93cSkardel if (cal_enable) 1113abb0f93cSkardel is->flags |= INFO_FLAG_CAL; 1114abb0f93cSkardel #endif /* REFCLOCK */ 1115abb0f93cSkardel if (kern_enable) 1116abb0f93cSkardel is->flags |= INFO_FLAG_KERNEL; 1117abb0f93cSkardel if (mon_enabled != MON_OFF) 1118abb0f93cSkardel is->flags |= INFO_FLAG_MONITOR; 1119abb0f93cSkardel if (ntp_enable) 1120abb0f93cSkardel is->flags |= INFO_FLAG_NTP; 1121ea66d795Schristos if (hardpps_enable) 1122abb0f93cSkardel is->flags |= INFO_FLAG_PPS_SYNC; 1123abb0f93cSkardel if (stats_control) 1124abb0f93cSkardel is->flags |= INFO_FLAG_FILEGEN; 1125abb0f93cSkardel is->bdelay = HTONS_FP(DTOFP(sys_bdelay)); 11262950cc38Schristos HTONL_UF(sys_authdelay.l_uf, &is->authdelay); 1127abb0f93cSkardel (void) more_pkt(); 1128abb0f93cSkardel flush_pkt(); 1129abb0f93cSkardel } 1130abb0f93cSkardel 1131abb0f93cSkardel 1132abb0f93cSkardel /* 1133abb0f93cSkardel * sys_stats - return system statistics 1134abb0f93cSkardel */ 1135abb0f93cSkardel static void 1136abb0f93cSkardel sys_stats( 1137abb0f93cSkardel sockaddr_u *srcadr, 11382950cc38Schristos endpt *inter, 1139abb0f93cSkardel struct req_pkt *inpkt 1140abb0f93cSkardel ) 1141abb0f93cSkardel { 1142abb0f93cSkardel register struct info_sys_stats *ss; 1143abb0f93cSkardel 1144abb0f93cSkardel ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt, 1145abb0f93cSkardel sizeof(struct info_sys_stats)); 1146abb0f93cSkardel ss->timeup = htonl((u_int32)current_time); 1147abb0f93cSkardel ss->timereset = htonl((u_int32)(current_time - sys_stattime)); 1148abb0f93cSkardel ss->denied = htonl((u_int32)sys_restricted); 1149abb0f93cSkardel ss->oldversionpkt = htonl((u_int32)sys_oldversion); 1150abb0f93cSkardel ss->newversionpkt = htonl((u_int32)sys_newversion); 1151abb0f93cSkardel ss->unknownversion = htonl((u_int32)sys_declined); 1152abb0f93cSkardel ss->badlength = htonl((u_int32)sys_badlength); 1153abb0f93cSkardel ss->processed = htonl((u_int32)sys_processed); 1154abb0f93cSkardel ss->badauth = htonl((u_int32)sys_badauth); 1155abb0f93cSkardel ss->limitrejected = htonl((u_int32)sys_limitrejected); 1156abb0f93cSkardel ss->received = htonl((u_int32)sys_received); 11574eea345dSchristos ss->lamport = htonl((u_int32)sys_lamport); 11584eea345dSchristos ss->tsrounding = htonl((u_int32)sys_tsrounding); 1159abb0f93cSkardel (void) more_pkt(); 1160abb0f93cSkardel flush_pkt(); 1161abb0f93cSkardel } 1162abb0f93cSkardel 1163abb0f93cSkardel 1164abb0f93cSkardel /* 1165abb0f93cSkardel * mem_stats - return memory statistics 1166abb0f93cSkardel */ 1167abb0f93cSkardel static void 1168abb0f93cSkardel mem_stats( 1169abb0f93cSkardel sockaddr_u *srcadr, 11702950cc38Schristos endpt *inter, 1171abb0f93cSkardel struct req_pkt *inpkt 1172abb0f93cSkardel ) 1173abb0f93cSkardel { 1174abb0f93cSkardel register struct info_mem_stats *ms; 1175abb0f93cSkardel register int i; 1176abb0f93cSkardel 1177abb0f93cSkardel ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt, 1178abb0f93cSkardel sizeof(struct info_mem_stats)); 1179abb0f93cSkardel 1180abb0f93cSkardel ms->timereset = htonl((u_int32)(current_time - peer_timereset)); 1181abb0f93cSkardel ms->totalpeermem = htons((u_short)total_peer_structs); 1182abb0f93cSkardel ms->freepeermem = htons((u_short)peer_free_count); 1183abb0f93cSkardel ms->findpeer_calls = htonl((u_int32)findpeer_calls); 1184abb0f93cSkardel ms->allocations = htonl((u_int32)peer_allocations); 1185abb0f93cSkardel ms->demobilizations = htonl((u_int32)peer_demobilizations); 1186abb0f93cSkardel 11872950cc38Schristos for (i = 0; i < NTP_HASH_SIZE; i++) 11882950cc38Schristos ms->hashcount[i] = (u_char) 118950c1baceSchristos min((u_int)peer_hash_count[i], UCHAR_MAX); 1190abb0f93cSkardel 119168dbbb44Schristos (void) more_pkt(); 1192abb0f93cSkardel flush_pkt(); 1193abb0f93cSkardel } 1194abb0f93cSkardel 1195abb0f93cSkardel 1196abb0f93cSkardel /* 1197abb0f93cSkardel * io_stats - return io statistics 1198abb0f93cSkardel */ 1199abb0f93cSkardel static void 1200abb0f93cSkardel io_stats( 1201abb0f93cSkardel sockaddr_u *srcadr, 12022950cc38Schristos endpt *inter, 1203abb0f93cSkardel struct req_pkt *inpkt 1204abb0f93cSkardel ) 1205abb0f93cSkardel { 12062950cc38Schristos struct info_io_stats *io; 1207abb0f93cSkardel 1208abb0f93cSkardel io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt, 1209abb0f93cSkardel sizeof(struct info_io_stats)); 1210abb0f93cSkardel 1211abb0f93cSkardel io->timereset = htonl((u_int32)(current_time - io_timereset)); 1212abb0f93cSkardel io->totalrecvbufs = htons((u_short) total_recvbuffs()); 1213abb0f93cSkardel io->freerecvbufs = htons((u_short) free_recvbuffs()); 1214abb0f93cSkardel io->fullrecvbufs = htons((u_short) full_recvbuffs()); 1215abb0f93cSkardel io->lowwater = htons((u_short) lowater_additions()); 1216abb0f93cSkardel io->dropped = htonl((u_int32)packets_dropped); 1217abb0f93cSkardel io->ignored = htonl((u_int32)packets_ignored); 1218abb0f93cSkardel io->received = htonl((u_int32)packets_received); 1219abb0f93cSkardel io->sent = htonl((u_int32)packets_sent); 1220abb0f93cSkardel io->notsent = htonl((u_int32)packets_notsent); 1221abb0f93cSkardel io->interrupts = htonl((u_int32)handler_calls); 1222abb0f93cSkardel io->int_received = htonl((u_int32)handler_pkts); 1223abb0f93cSkardel 1224abb0f93cSkardel (void) more_pkt(); 1225abb0f93cSkardel flush_pkt(); 1226abb0f93cSkardel } 1227abb0f93cSkardel 1228abb0f93cSkardel 1229abb0f93cSkardel /* 1230abb0f93cSkardel * timer_stats - return timer statistics 1231abb0f93cSkardel */ 1232abb0f93cSkardel static void 1233abb0f93cSkardel timer_stats( 1234abb0f93cSkardel sockaddr_u * srcadr, 12352950cc38Schristos endpt * inter, 1236abb0f93cSkardel struct req_pkt * inpkt 1237abb0f93cSkardel ) 1238abb0f93cSkardel { 12393123f114Skardel struct info_timer_stats * ts; 12403123f114Skardel u_long sincereset; 1241abb0f93cSkardel 12423123f114Skardel ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, 12433123f114Skardel inpkt, sizeof(*ts)); 1244abb0f93cSkardel 12453123f114Skardel sincereset = current_time - timer_timereset; 12463123f114Skardel ts->timereset = htonl((u_int32)sincereset); 12473123f114Skardel ts->alarms = ts->timereset; 12483123f114Skardel ts->overflows = htonl((u_int32)alarm_overflow); 1249abb0f93cSkardel ts->xmtcalls = htonl((u_int32)timer_xmtcalls); 1250abb0f93cSkardel 1251abb0f93cSkardel (void) more_pkt(); 1252abb0f93cSkardel flush_pkt(); 1253abb0f93cSkardel } 1254abb0f93cSkardel 1255abb0f93cSkardel 1256abb0f93cSkardel /* 1257abb0f93cSkardel * loop_info - return the current state of the loop filter 1258abb0f93cSkardel */ 1259abb0f93cSkardel static void 1260abb0f93cSkardel loop_info( 1261abb0f93cSkardel sockaddr_u *srcadr, 12622950cc38Schristos endpt *inter, 1263abb0f93cSkardel struct req_pkt *inpkt 1264abb0f93cSkardel ) 1265abb0f93cSkardel { 12662950cc38Schristos struct info_loop *li; 1267abb0f93cSkardel l_fp ltmp; 1268abb0f93cSkardel 1269abb0f93cSkardel li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt, 1270abb0f93cSkardel sizeof(struct info_loop)); 1271abb0f93cSkardel 1272abb0f93cSkardel DTOLFP(last_offset, <mp); 1273abb0f93cSkardel HTONL_FP(<mp, &li->last_offset); 1274abb0f93cSkardel DTOLFP(drift_comp * 1e6, <mp); 1275abb0f93cSkardel HTONL_FP(<mp, &li->drift_comp); 1276abb0f93cSkardel li->compliance = htonl((u_int32)(tc_counter)); 1277abb0f93cSkardel li->watchdog_timer = htonl((u_int32)(current_time - sys_epoch)); 1278abb0f93cSkardel 127968dbbb44Schristos (void) more_pkt(); 1280abb0f93cSkardel flush_pkt(); 1281abb0f93cSkardel } 1282abb0f93cSkardel 1283abb0f93cSkardel 1284abb0f93cSkardel /* 1285abb0f93cSkardel * do_conf - add a peer to the configuration list 1286abb0f93cSkardel */ 1287abb0f93cSkardel static void 1288abb0f93cSkardel do_conf( 1289abb0f93cSkardel sockaddr_u *srcadr, 12902950cc38Schristos endpt *inter, 1291abb0f93cSkardel struct req_pkt *inpkt 1292abb0f93cSkardel ) 1293abb0f93cSkardel { 12942950cc38Schristos u_short items; 12952950cc38Schristos size_t item_sz; 1296abb0f93cSkardel u_int fl; 12972950cc38Schristos char * datap; 1298abb0f93cSkardel struct conf_peer temp_cp; 1299abb0f93cSkardel sockaddr_u peeraddr; 1300abb0f93cSkardel 1301abb0f93cSkardel /* 1302abb0f93cSkardel * Do a check of everything to see that it looks 1303abb0f93cSkardel * okay. If not, complain about it. Note we are 1304abb0f93cSkardel * very picky here. 1305abb0f93cSkardel */ 1306abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 13072950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 13082950cc38Schristos datap = inpkt->u.data; 13092950cc38Schristos if (item_sz > sizeof(temp_cp)) { 1310abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 1311abb0f93cSkardel return; 1312abb0f93cSkardel } 1313abb0f93cSkardel 1314abb0f93cSkardel while (items-- > 0) { 13152950cc38Schristos ZERO(temp_cp); 13162950cc38Schristos memcpy(&temp_cp, datap, item_sz); 1317abb0f93cSkardel ZERO_SOCK(&peeraddr); 1318abb0f93cSkardel 1319abb0f93cSkardel fl = 0; 1320abb0f93cSkardel if (temp_cp.flags & CONF_FLAG_PREFER) 1321abb0f93cSkardel fl |= FLAG_PREFER; 1322abb0f93cSkardel if (temp_cp.flags & CONF_FLAG_BURST) 1323abb0f93cSkardel fl |= FLAG_BURST; 1324abb0f93cSkardel if (temp_cp.flags & CONF_FLAG_IBURST) 1325abb0f93cSkardel fl |= FLAG_IBURST; 13262950cc38Schristos #ifdef AUTOKEY 1327abb0f93cSkardel if (temp_cp.flags & CONF_FLAG_SKEY) 1328abb0f93cSkardel fl |= FLAG_SKEY; 13292950cc38Schristos #endif /* AUTOKEY */ 13302950cc38Schristos if (client_v6_capable && temp_cp.v6_flag) { 1331abb0f93cSkardel AF(&peeraddr) = AF_INET6; 1332abb0f93cSkardel SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6; 1333abb0f93cSkardel } else { 1334abb0f93cSkardel AF(&peeraddr) = AF_INET; 1335abb0f93cSkardel NSRCADR(&peeraddr) = temp_cp.peeraddr; 1336abb0f93cSkardel /* 1337abb0f93cSkardel * Make sure the address is valid 1338abb0f93cSkardel */ 1339abb0f93cSkardel if (!ISREFCLOCKADR(&peeraddr) && 1340abb0f93cSkardel ISBADADR(&peeraddr)) { 1341abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 1342abb0f93cSkardel return; 1343abb0f93cSkardel } 1344abb0f93cSkardel 1345abb0f93cSkardel } 1346abb0f93cSkardel NSRCPORT(&peeraddr) = htons(NTP_PORT); 1347abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 13483123f114Skardel peeraddr.sa.sa_len = SOCKLEN(&peeraddr); 1349abb0f93cSkardel #endif 1350abb0f93cSkardel 135168dbbb44Schristos /* check mode value: 0 <= hmode <= 6 135268dbbb44Schristos * 135368dbbb44Schristos * There's no good global define for that limit, and 135468dbbb44Schristos * using a magic define is as good (or bad, actually) as 135568dbbb44Schristos * a magic number. So we use the highest possible peer 135668dbbb44Schristos * mode, and that is MODE_BCLIENT. 135768dbbb44Schristos * 135868dbbb44Schristos * [Bug 3009] claims that a problem occurs for hmode > 7, 135968dbbb44Schristos * but the code in ntp_peer.c indicates trouble for any 136068dbbb44Schristos * hmode > 6 ( --> MODE_BCLIENT). 136168dbbb44Schristos */ 136268dbbb44Schristos if (temp_cp.hmode > MODE_BCLIENT) { 136368dbbb44Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 136468dbbb44Schristos return; 136568dbbb44Schristos } 136668dbbb44Schristos 136768dbbb44Schristos /* Any more checks on the values? Unchecked at this 136868dbbb44Schristos * point: 136968dbbb44Schristos * - version 137068dbbb44Schristos * - ttl 137168dbbb44Schristos * - keyid 137268dbbb44Schristos * 137368dbbb44Schristos * - minpoll/maxpoll, but they are treated properly 137468dbbb44Schristos * for all cases internally. Checking not necessary. 13754eea345dSchristos * 13764eea345dSchristos * Note that we ignore any previously-specified ippeerlimit. 13774eea345dSchristos * If we're told to create the peer, we create the peer. 137868dbbb44Schristos */ 137968dbbb44Schristos 138068dbbb44Schristos /* finally create the peer */ 13814eea345dSchristos if (peer_config(&peeraddr, NULL, NULL, -1, 1382abb0f93cSkardel temp_cp.hmode, temp_cp.version, temp_cp.minpoll, 1383abb0f93cSkardel temp_cp.maxpoll, fl, temp_cp.ttl, temp_cp.keyid, 138468dbbb44Schristos NULL) == 0) 138568dbbb44Schristos { 1386abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 1387abb0f93cSkardel return; 1388abb0f93cSkardel } 1389abb0f93cSkardel 13902950cc38Schristos datap += item_sz; 1391abb0f93cSkardel } 1392abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 1393abb0f93cSkardel } 1394abb0f93cSkardel 1395abb0f93cSkardel 1396abb0f93cSkardel /* 1397abb0f93cSkardel * do_unconf - remove a peer from the configuration list 1398abb0f93cSkardel */ 1399abb0f93cSkardel static void 1400abb0f93cSkardel do_unconf( 1401abb0f93cSkardel sockaddr_u * srcadr, 14022950cc38Schristos endpt * inter, 1403abb0f93cSkardel struct req_pkt *inpkt 1404abb0f93cSkardel ) 1405abb0f93cSkardel { 14062950cc38Schristos u_short items; 14072950cc38Schristos size_t item_sz; 14082950cc38Schristos char * datap; 1409abb0f93cSkardel struct conf_unpeer temp_cp; 14102950cc38Schristos struct peer * p; 1411abb0f93cSkardel sockaddr_u peeraddr; 141268dbbb44Schristos int loops; 1413abb0f93cSkardel 1414abb0f93cSkardel /* 1415abb0f93cSkardel * This is a bit unstructured, but I like to be careful. 1416abb0f93cSkardel * We check to see that every peer exists and is actually 1417abb0f93cSkardel * configured. If so, we remove them. If not, we return 1418abb0f93cSkardel * an error. 141968dbbb44Schristos * 142068dbbb44Schristos * [Bug 3011] Even if we checked all peers given in the request 142168dbbb44Schristos * in a dry run, there's still a chance that the caller played 142268dbbb44Schristos * unfair and gave the same peer multiple times. So we still 142368dbbb44Schristos * have to be prepared for nasty surprises in the second run ;) 1424abb0f93cSkardel */ 142568dbbb44Schristos 142668dbbb44Schristos /* basic consistency checks */ 14272950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 14282950cc38Schristos if (item_sz > sizeof(temp_cp)) { 14292950cc38Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 14302950cc38Schristos return; 14312950cc38Schristos } 1432abb0f93cSkardel 143368dbbb44Schristos /* now do two runs: first a dry run, then a busy one */ 143468dbbb44Schristos for (loops = 0; loops != 2; ++loops) { 143568dbbb44Schristos items = INFO_NITEMS(inpkt->err_nitems); 143668dbbb44Schristos datap = inpkt->u.data; 143768dbbb44Schristos while (items-- > 0) { 143868dbbb44Schristos /* copy from request to local */ 14392950cc38Schristos ZERO(temp_cp); 14402950cc38Schristos memcpy(&temp_cp, datap, item_sz); 144168dbbb44Schristos /* get address structure */ 1442abb0f93cSkardel ZERO_SOCK(&peeraddr); 1443abb0f93cSkardel if (client_v6_capable && temp_cp.v6_flag) { 1444abb0f93cSkardel AF(&peeraddr) = AF_INET6; 1445abb0f93cSkardel SOCK_ADDR6(&peeraddr) = temp_cp.peeraddr6; 1446abb0f93cSkardel } else { 1447abb0f93cSkardel AF(&peeraddr) = AF_INET; 1448abb0f93cSkardel NSRCADR(&peeraddr) = temp_cp.peeraddr; 1449abb0f93cSkardel } 1450abb0f93cSkardel SET_PORT(&peeraddr, NTP_PORT); 1451abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 14523123f114Skardel peeraddr.sa.sa_len = SOCKLEN(&peeraddr); 1453abb0f93cSkardel #endif 145468dbbb44Schristos DPRINTF(1, ("searching for %s\n", 145568dbbb44Schristos stoa(&peeraddr))); 145668dbbb44Schristos 145768dbbb44Schristos /* search for matching configred(!) peer */ 14582950cc38Schristos p = NULL; 145968dbbb44Schristos do { 146068dbbb44Schristos p = findexistingpeer( 14614eea345dSchristos &peeraddr, NULL, p, -1, 0, NULL); 146268dbbb44Schristos } while (p && !(FLAG_CONFIG & p->flags)); 1463abb0f93cSkardel 146468dbbb44Schristos if (!loops && !p) { 146568dbbb44Schristos /* Item not found in dry run -- bail! */ 146668dbbb44Schristos req_ack(srcadr, inter, inpkt, 146768dbbb44Schristos INFO_ERR_NODATA); 1468abb0f93cSkardel return; 146968dbbb44Schristos } else if (loops && p) { 147068dbbb44Schristos /* Item found in busy run -- remove! */ 14712950cc38Schristos peer_clear(p, "GONE"); 14722950cc38Schristos unpeer(p); 147368dbbb44Schristos } 14742950cc38Schristos datap += item_sz; 1475abb0f93cSkardel } 147668dbbb44Schristos } 1477abb0f93cSkardel 147868dbbb44Schristos /* report success */ 1479abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 1480abb0f93cSkardel } 1481abb0f93cSkardel 1482abb0f93cSkardel 1483abb0f93cSkardel /* 1484abb0f93cSkardel * set_sys_flag - set system flags 1485abb0f93cSkardel */ 1486abb0f93cSkardel static void 1487abb0f93cSkardel set_sys_flag( 1488abb0f93cSkardel sockaddr_u *srcadr, 14892950cc38Schristos endpt *inter, 1490abb0f93cSkardel struct req_pkt *inpkt 1491abb0f93cSkardel ) 1492abb0f93cSkardel { 1493abb0f93cSkardel setclr_flags(srcadr, inter, inpkt, 1); 1494abb0f93cSkardel } 1495abb0f93cSkardel 1496abb0f93cSkardel 1497abb0f93cSkardel /* 1498abb0f93cSkardel * clr_sys_flag - clear system flags 1499abb0f93cSkardel */ 1500abb0f93cSkardel static void 1501abb0f93cSkardel clr_sys_flag( 1502abb0f93cSkardel sockaddr_u *srcadr, 15032950cc38Schristos endpt *inter, 1504abb0f93cSkardel struct req_pkt *inpkt 1505abb0f93cSkardel ) 1506abb0f93cSkardel { 1507abb0f93cSkardel setclr_flags(srcadr, inter, inpkt, 0); 1508abb0f93cSkardel } 1509abb0f93cSkardel 1510abb0f93cSkardel 1511abb0f93cSkardel /* 1512abb0f93cSkardel * setclr_flags - do the grunge work of flag setting/clearing 1513abb0f93cSkardel */ 1514abb0f93cSkardel static void 1515abb0f93cSkardel setclr_flags( 1516abb0f93cSkardel sockaddr_u *srcadr, 15172950cc38Schristos endpt *inter, 1518abb0f93cSkardel struct req_pkt *inpkt, 1519abb0f93cSkardel u_long set 1520abb0f93cSkardel ) 1521abb0f93cSkardel { 15223123f114Skardel struct conf_sys_flags *sf; 15233123f114Skardel u_int32 flags; 1524abb0f93cSkardel 1525abb0f93cSkardel if (INFO_NITEMS(inpkt->err_nitems) > 1) { 1526abb0f93cSkardel msyslog(LOG_ERR, "setclr_flags: err_nitems > 1"); 1527abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 1528abb0f93cSkardel return; 1529abb0f93cSkardel } 1530abb0f93cSkardel 15312950cc38Schristos sf = (struct conf_sys_flags *)&inpkt->u; 15323123f114Skardel flags = ntohl(sf->flags); 1533abb0f93cSkardel 1534abb0f93cSkardel if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | 1535abb0f93cSkardel SYS_FLAG_NTP | SYS_FLAG_KERNEL | SYS_FLAG_MONITOR | 1536abb0f93cSkardel SYS_FLAG_FILEGEN | SYS_FLAG_AUTH | SYS_FLAG_CAL)) { 1537abb0f93cSkardel msyslog(LOG_ERR, "setclr_flags: extra flags: %#x", 1538abb0f93cSkardel flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_PPS | 1539abb0f93cSkardel SYS_FLAG_NTP | SYS_FLAG_KERNEL | 1540abb0f93cSkardel SYS_FLAG_MONITOR | SYS_FLAG_FILEGEN | 1541abb0f93cSkardel SYS_FLAG_AUTH | SYS_FLAG_CAL)); 1542abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 1543abb0f93cSkardel return; 1544abb0f93cSkardel } 1545abb0f93cSkardel 1546abb0f93cSkardel if (flags & SYS_FLAG_BCLIENT) 1547abb0f93cSkardel proto_config(PROTO_BROADCLIENT, set, 0., NULL); 1548abb0f93cSkardel if (flags & SYS_FLAG_PPS) 1549abb0f93cSkardel proto_config(PROTO_PPS, set, 0., NULL); 1550abb0f93cSkardel if (flags & SYS_FLAG_NTP) 1551abb0f93cSkardel proto_config(PROTO_NTP, set, 0., NULL); 1552abb0f93cSkardel if (flags & SYS_FLAG_KERNEL) 1553abb0f93cSkardel proto_config(PROTO_KERNEL, set, 0., NULL); 1554abb0f93cSkardel if (flags & SYS_FLAG_MONITOR) 1555abb0f93cSkardel proto_config(PROTO_MONITOR, set, 0., NULL); 1556abb0f93cSkardel if (flags & SYS_FLAG_FILEGEN) 1557abb0f93cSkardel proto_config(PROTO_FILEGEN, set, 0., NULL); 1558abb0f93cSkardel if (flags & SYS_FLAG_AUTH) 1559abb0f93cSkardel proto_config(PROTO_AUTHENTICATE, set, 0., NULL); 1560abb0f93cSkardel if (flags & SYS_FLAG_CAL) 1561abb0f93cSkardel proto_config(PROTO_CAL, set, 0., NULL); 1562abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 1563abb0f93cSkardel } 1564abb0f93cSkardel 156568dbbb44Schristos /* There have been some issues with the restrict list processing, 156668dbbb44Schristos * ranging from problems with deep recursion (resulting in stack 156768dbbb44Schristos * overflows) and overfull reply buffers. 156868dbbb44Schristos * 156968dbbb44Schristos * To avoid this trouble the list reversal is done iteratively using a 157068dbbb44Schristos * scratch pad. 157168dbbb44Schristos */ 1572*9e9fa66aSchristos typedef struct RestrictStack4 RestrictStack4T; 1573*9e9fa66aSchristos struct RestrictStack4 { 1574*9e9fa66aSchristos RestrictStack4T *link; 157568dbbb44Schristos size_t fcnt; 1576*9e9fa66aSchristos const struct restrict_4 *pres[63]; 157768dbbb44Schristos }; 157868dbbb44Schristos 157968dbbb44Schristos static size_t 1580*9e9fa66aSchristos getStackSheetSize4( 1581*9e9fa66aSchristos RestrictStack4T *sp 158268dbbb44Schristos ) 158368dbbb44Schristos { 158468dbbb44Schristos if (sp) 158568dbbb44Schristos return sizeof(sp->pres)/sizeof(sp->pres[0]); 158668dbbb44Schristos return 0u; 158768dbbb44Schristos } 158868dbbb44Schristos 158968dbbb44Schristos static int/*BOOL*/ 1590*9e9fa66aSchristos pushRestriction4( 1591*9e9fa66aSchristos RestrictStack4T **spp, 1592*9e9fa66aSchristos const struct restrict_4 *ptr 159368dbbb44Schristos ) 159468dbbb44Schristos { 1595*9e9fa66aSchristos RestrictStack4T *sp; 159668dbbb44Schristos 159768dbbb44Schristos if (NULL == (sp = *spp) || 0 == sp->fcnt) { 159868dbbb44Schristos /* need another sheet in the scratch pad */ 159968dbbb44Schristos sp = emalloc(sizeof(*sp)); 160068dbbb44Schristos sp->link = *spp; 1601*9e9fa66aSchristos sp->fcnt = getStackSheetSize4(sp); 160268dbbb44Schristos *spp = sp; 160368dbbb44Schristos } 160468dbbb44Schristos sp->pres[--sp->fcnt] = ptr; 160568dbbb44Schristos return TRUE; 160668dbbb44Schristos } 160768dbbb44Schristos 160868dbbb44Schristos static int/*BOOL*/ 1609*9e9fa66aSchristos popRestriction4( 1610*9e9fa66aSchristos RestrictStack4T **spp, 1611*9e9fa66aSchristos const struct restrict_4 **opp 161268dbbb44Schristos ) 161368dbbb44Schristos { 1614*9e9fa66aSchristos RestrictStack4T *sp; 161568dbbb44Schristos 1616*9e9fa66aSchristos if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize4(sp)) 161768dbbb44Schristos return FALSE; 161868dbbb44Schristos 161968dbbb44Schristos *opp = sp->pres[sp->fcnt++]; 1620*9e9fa66aSchristos if (sp->fcnt >= getStackSheetSize4(sp)) { 162168dbbb44Schristos /* discard sheet from scratch pad */ 162268dbbb44Schristos *spp = sp->link; 162368dbbb44Schristos free(sp); 162468dbbb44Schristos } 162568dbbb44Schristos return TRUE; 162668dbbb44Schristos } 162768dbbb44Schristos 162868dbbb44Schristos static void 1629*9e9fa66aSchristos flushRestrictionStack4( 1630*9e9fa66aSchristos RestrictStack4T **spp 163168dbbb44Schristos ) 163268dbbb44Schristos { 1633*9e9fa66aSchristos RestrictStack4T *sp; 163468dbbb44Schristos 163568dbbb44Schristos while (NULL != (sp = *spp)) { 163668dbbb44Schristos *spp = sp->link; 163768dbbb44Schristos free(sp); 163868dbbb44Schristos } 163968dbbb44Schristos } 164068dbbb44Schristos 16413123f114Skardel /* 164268dbbb44Schristos * list_restrict4 - iterative helper for list_restrict dumps IPv4 16433123f114Skardel * restriction list in reverse order. 16443123f114Skardel */ 16453123f114Skardel static void 16463123f114Skardel list_restrict4( 1647*9e9fa66aSchristos const struct restrict_4 * res, 16483123f114Skardel struct info_restrict ** ppir 16493123f114Skardel ) 16503123f114Skardel { 1651*9e9fa66aSchristos RestrictStack4T * rpad; 16523123f114Skardel struct info_restrict * pir; 16533123f114Skardel 16543123f114Skardel pir = *ppir; 165568dbbb44Schristos for (rpad = NULL; res; res = res->link) 1656*9e9fa66aSchristos if (!pushRestriction4(&rpad, res)) 165768dbbb44Schristos break; 165868dbbb44Schristos 1659*9e9fa66aSchristos while (pir && popRestriction4(&rpad, &res)) { 1660*9e9fa66aSchristos pir->addr = htonl(res->v4.addr); 16613123f114Skardel if (client_v6_capable) 16623123f114Skardel pir->v6_flag = 0; 1663*9e9fa66aSchristos pir->mask = htonl(res->v4.mask); 1664*9e9fa66aSchristos pir->count = htonl(res->ri.count); 1665*9e9fa66aSchristos pir->rflags = htons(res->ri.rflags); 1666*9e9fa66aSchristos pir->mflags = htons(res->ri.mflags); 166768dbbb44Schristos pir = (struct info_restrict *)more_pkt(); 166868dbbb44Schristos } 1669*9e9fa66aSchristos flushRestrictionStack4(&rpad); 167068dbbb44Schristos *ppir = pir; 16713123f114Skardel } 16723123f114Skardel 1673*9e9fa66aSchristos typedef struct RestrictStack6 RestrictStack6T; 1674*9e9fa66aSchristos struct RestrictStack6 { 1675*9e9fa66aSchristos RestrictStack6T *link; 1676*9e9fa66aSchristos size_t fcnt; 1677*9e9fa66aSchristos const struct restrict_6 *pres[63]; 1678*9e9fa66aSchristos }; 1679*9e9fa66aSchristos 1680*9e9fa66aSchristos static size_t 1681*9e9fa66aSchristos getStackSheetSize6( 1682*9e9fa66aSchristos RestrictStack6T *sp 1683*9e9fa66aSchristos ) 1684*9e9fa66aSchristos { 1685*9e9fa66aSchristos if (sp) 1686*9e9fa66aSchristos return sizeof(sp->pres)/sizeof(sp->pres[0]); 1687*9e9fa66aSchristos return 0u; 1688*9e9fa66aSchristos } 1689*9e9fa66aSchristos 1690*9e9fa66aSchristos static int/*BOOL*/ 1691*9e9fa66aSchristos pushRestriction6( 1692*9e9fa66aSchristos RestrictStack6T **spp, 1693*9e9fa66aSchristos const struct restrict_6 *ptr 1694*9e9fa66aSchristos ) 1695*9e9fa66aSchristos { 1696*9e9fa66aSchristos RestrictStack6T *sp; 1697*9e9fa66aSchristos 1698*9e9fa66aSchristos if (NULL == (sp = *spp) || 0 == sp->fcnt) { 1699*9e9fa66aSchristos /* need another sheet in the scratch pad */ 1700*9e9fa66aSchristos sp = emalloc(sizeof(*sp)); 1701*9e9fa66aSchristos sp->link = *spp; 1702*9e9fa66aSchristos sp->fcnt = getStackSheetSize6(sp); 1703*9e9fa66aSchristos *spp = sp; 1704*9e9fa66aSchristos } 1705*9e9fa66aSchristos sp->pres[--sp->fcnt] = ptr; 1706*9e9fa66aSchristos return TRUE; 1707*9e9fa66aSchristos } 1708*9e9fa66aSchristos 1709*9e9fa66aSchristos static int/*BOOL*/ 1710*9e9fa66aSchristos popRestriction6( 1711*9e9fa66aSchristos RestrictStack6T **spp, 1712*9e9fa66aSchristos const struct restrict_6 **opp 1713*9e9fa66aSchristos ) 1714*9e9fa66aSchristos { 1715*9e9fa66aSchristos RestrictStack6T *sp; 1716*9e9fa66aSchristos 1717*9e9fa66aSchristos if (NULL == (sp = *spp) || sp->fcnt >= getStackSheetSize6(sp)) 1718*9e9fa66aSchristos return FALSE; 1719*9e9fa66aSchristos 1720*9e9fa66aSchristos *opp = sp->pres[sp->fcnt++]; 1721*9e9fa66aSchristos if (sp->fcnt >= getStackSheetSize6(sp)) { 1722*9e9fa66aSchristos /* discard sheet from scratch pad */ 1723*9e9fa66aSchristos *spp = sp->link; 1724*9e9fa66aSchristos free(sp); 1725*9e9fa66aSchristos } 1726*9e9fa66aSchristos return TRUE; 1727*9e9fa66aSchristos } 1728*9e9fa66aSchristos 1729*9e9fa66aSchristos static void 1730*9e9fa66aSchristos flushRestrictionStack6( 1731*9e9fa66aSchristos RestrictStack6T **spp 1732*9e9fa66aSchristos ) 1733*9e9fa66aSchristos { 1734*9e9fa66aSchristos RestrictStack6T *sp; 1735*9e9fa66aSchristos 1736*9e9fa66aSchristos while (NULL != (sp = *spp)) { 1737*9e9fa66aSchristos *spp = sp->link; 1738*9e9fa66aSchristos free(sp); 1739*9e9fa66aSchristos } 1740*9e9fa66aSchristos } 1741*9e9fa66aSchristos 17423123f114Skardel /* 174368dbbb44Schristos * list_restrict6 - iterative helper for list_restrict dumps IPv6 17443123f114Skardel * restriction list in reverse order. 17453123f114Skardel */ 17463123f114Skardel static void 17473123f114Skardel list_restrict6( 1748*9e9fa66aSchristos const struct restrict_6 * res, 17493123f114Skardel struct info_restrict ** ppir 17503123f114Skardel ) 17513123f114Skardel { 1752*9e9fa66aSchristos RestrictStack6T * rpad; 17533123f114Skardel struct info_restrict * pir; 17543123f114Skardel 17553123f114Skardel pir = *ppir; 175668dbbb44Schristos for (rpad = NULL; res; res = res->link) 1757*9e9fa66aSchristos if (!pushRestriction6(&rpad, res)) 175868dbbb44Schristos break; 175968dbbb44Schristos 1760*9e9fa66aSchristos while (pir && popRestriction6(&rpad, &res)) { 1761*9e9fa66aSchristos pir->addr6 = res->v6.addr; 1762*9e9fa66aSchristos pir->mask6 = res->v6.mask; 17633123f114Skardel pir->v6_flag = 1; 1764*9e9fa66aSchristos pir->count = htonl(res->ri.count); 1765*9e9fa66aSchristos pir->rflags = htons(res->ri.rflags); 1766*9e9fa66aSchristos pir->mflags = htons(res->ri.mflags); 176768dbbb44Schristos pir = (struct info_restrict *)more_pkt(); 176868dbbb44Schristos } 1769*9e9fa66aSchristos flushRestrictionStack6(&rpad); 177068dbbb44Schristos *ppir = pir; 17713123f114Skardel } 17723123f114Skardel 1773abb0f93cSkardel 1774abb0f93cSkardel /* 1775abb0f93cSkardel * list_restrict - return the restrict list 1776abb0f93cSkardel */ 1777abb0f93cSkardel static void 1778abb0f93cSkardel list_restrict( 1779abb0f93cSkardel sockaddr_u *srcadr, 17802950cc38Schristos endpt *inter, 1781abb0f93cSkardel struct req_pkt *inpkt 1782abb0f93cSkardel ) 1783abb0f93cSkardel { 17843123f114Skardel struct info_restrict *ir; 1785abb0f93cSkardel 17863123f114Skardel DPRINTF(3, ("wants restrict list summary\n")); 1787abb0f93cSkardel 1788abb0f93cSkardel ir = (struct info_restrict *)prepare_pkt(srcadr, inter, inpkt, 1789abb0f93cSkardel v6sizeof(struct info_restrict)); 1790abb0f93cSkardel 17913123f114Skardel /* 17923123f114Skardel * The restriction lists are kept sorted in the reverse order 17933123f114Skardel * than they were originally. To preserve the output semantics, 179468dbbb44Schristos * dump each list in reverse order. The workers take care of that. 17953123f114Skardel */ 17963123f114Skardel list_restrict4(restrictlist4, &ir); 1797abb0f93cSkardel if (client_v6_capable) 17983123f114Skardel list_restrict6(restrictlist6, &ir); 1799abb0f93cSkardel flush_pkt(); 1800abb0f93cSkardel } 1801abb0f93cSkardel 1802abb0f93cSkardel 1803abb0f93cSkardel /* 1804abb0f93cSkardel * do_resaddflags - add flags to a restrict entry (or create one) 1805abb0f93cSkardel */ 1806abb0f93cSkardel static void 1807abb0f93cSkardel do_resaddflags( 1808abb0f93cSkardel sockaddr_u *srcadr, 18092950cc38Schristos endpt *inter, 1810abb0f93cSkardel struct req_pkt *inpkt 1811abb0f93cSkardel ) 1812abb0f93cSkardel { 1813abb0f93cSkardel do_restrict(srcadr, inter, inpkt, RESTRICT_FLAGS); 1814abb0f93cSkardel } 1815abb0f93cSkardel 1816abb0f93cSkardel 1817abb0f93cSkardel 1818abb0f93cSkardel /* 1819abb0f93cSkardel * do_ressubflags - remove flags from a restrict entry 1820abb0f93cSkardel */ 1821abb0f93cSkardel static void 1822abb0f93cSkardel do_ressubflags( 1823abb0f93cSkardel sockaddr_u *srcadr, 18242950cc38Schristos endpt *inter, 1825abb0f93cSkardel struct req_pkt *inpkt 1826abb0f93cSkardel ) 1827abb0f93cSkardel { 1828abb0f93cSkardel do_restrict(srcadr, inter, inpkt, RESTRICT_UNFLAG); 1829abb0f93cSkardel } 1830abb0f93cSkardel 1831abb0f93cSkardel 1832abb0f93cSkardel /* 1833abb0f93cSkardel * do_unrestrict - remove a restrict entry from the list 1834abb0f93cSkardel */ 1835abb0f93cSkardel static void 1836abb0f93cSkardel do_unrestrict( 1837abb0f93cSkardel sockaddr_u *srcadr, 18382950cc38Schristos endpt *inter, 1839abb0f93cSkardel struct req_pkt *inpkt 1840abb0f93cSkardel ) 1841abb0f93cSkardel { 1842abb0f93cSkardel do_restrict(srcadr, inter, inpkt, RESTRICT_REMOVE); 1843abb0f93cSkardel } 1844abb0f93cSkardel 1845abb0f93cSkardel 1846abb0f93cSkardel /* 1847abb0f93cSkardel * do_restrict - do the dirty stuff of dealing with restrictions 1848abb0f93cSkardel */ 1849abb0f93cSkardel static void 1850abb0f93cSkardel do_restrict( 1851abb0f93cSkardel sockaddr_u *srcadr, 18522950cc38Schristos endpt *inter, 1853abb0f93cSkardel struct req_pkt *inpkt, 18544eea345dSchristos restrict_op op 1855abb0f93cSkardel ) 1856abb0f93cSkardel { 18572950cc38Schristos char * datap; 18582950cc38Schristos struct conf_restrict cr; 18592950cc38Schristos u_short items; 18602950cc38Schristos size_t item_sz; 1861abb0f93cSkardel sockaddr_u matchaddr; 1862abb0f93cSkardel sockaddr_u matchmask; 1863abb0f93cSkardel int bad; 1864eabc0478Schristos int/*BOOL*/ success; 1865abb0f93cSkardel 18664eea345dSchristos switch(op) { 18674eea345dSchristos case RESTRICT_FLAGS: 18684eea345dSchristos case RESTRICT_UNFLAG: 18694eea345dSchristos case RESTRICT_REMOVE: 18704eea345dSchristos case RESTRICT_REMOVEIF: 18714eea345dSchristos break; 18724eea345dSchristos 18734eea345dSchristos default: 18744eea345dSchristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 18754eea345dSchristos return; 18764eea345dSchristos } 18774eea345dSchristos 1878abb0f93cSkardel /* 1879abb0f93cSkardel * Do a check of the flags to make sure that only 1880abb0f93cSkardel * the NTPPORT flag is set, if any. If not, complain 1881abb0f93cSkardel * about it. Note we are very picky here. 1882abb0f93cSkardel */ 1883abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 18842950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 18852950cc38Schristos datap = inpkt->u.data; 18862950cc38Schristos if (item_sz > sizeof(cr)) { 18872950cc38Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 18882950cc38Schristos return; 18892950cc38Schristos } 1890abb0f93cSkardel 18914eea345dSchristos bad = 0; 1892abb0f93cSkardel while (items-- > 0 && !bad) { 18932950cc38Schristos memcpy(&cr, datap, item_sz); 1894cdfa2a7eSchristos cr.flags = ntohs(cr.flags); /* XXX */ 18952950cc38Schristos cr.mflags = ntohs(cr.mflags); 18962950cc38Schristos if (~RESM_NTPONLY & cr.mflags) 1897abb0f93cSkardel bad |= 1; 18982950cc38Schristos if (~RES_ALLFLAGS & cr.flags) 1899abb0f93cSkardel bad |= 2; 19002950cc38Schristos if (INADDR_ANY != cr.mask) { 19012950cc38Schristos if (client_v6_capable && cr.v6_flag) { 19022950cc38Schristos if (IN6_IS_ADDR_UNSPECIFIED(&cr.addr6)) 1903abb0f93cSkardel bad |= 4; 19042950cc38Schristos } else { 19052950cc38Schristos if (INADDR_ANY == cr.addr) 1906abb0f93cSkardel bad |= 8; 1907abb0f93cSkardel } 19082950cc38Schristos } 19092950cc38Schristos datap += item_sz; 1910abb0f93cSkardel } 1911abb0f93cSkardel 1912abb0f93cSkardel if (bad) { 1913eabc0478Schristos msyslog(LOG_ERR, "%s: bad = 0x%x", __func__, bad); 1914abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 1915abb0f93cSkardel return; 1916abb0f93cSkardel } 1917abb0f93cSkardel 1918abb0f93cSkardel /* 1919af12ab5eSchristos * Looks okay, try it out. Needs to reload data pointer and 1920af12ab5eSchristos * item counter. (Talos-CAN-0052) 1921abb0f93cSkardel */ 1922abb0f93cSkardel ZERO_SOCK(&matchaddr); 1923abb0f93cSkardel ZERO_SOCK(&matchmask); 1924af12ab5eSchristos items = INFO_NITEMS(inpkt->err_nitems); 19252950cc38Schristos datap = inpkt->u.data; 1926abb0f93cSkardel 1927abb0f93cSkardel while (items-- > 0) { 19282950cc38Schristos memcpy(&cr, datap, item_sz); 1929cdfa2a7eSchristos cr.flags = ntohs(cr.flags); /* XXX: size */ 19302950cc38Schristos cr.mflags = ntohs(cr.mflags); 19314eea345dSchristos cr.ippeerlimit = ntohs(cr.ippeerlimit); 19322950cc38Schristos if (client_v6_capable && cr.v6_flag) { 1933abb0f93cSkardel AF(&matchaddr) = AF_INET6; 1934abb0f93cSkardel AF(&matchmask) = AF_INET6; 19352950cc38Schristos SOCK_ADDR6(&matchaddr) = cr.addr6; 19362950cc38Schristos SOCK_ADDR6(&matchmask) = cr.mask6; 1937abb0f93cSkardel } else { 1938abb0f93cSkardel AF(&matchaddr) = AF_INET; 1939abb0f93cSkardel AF(&matchmask) = AF_INET; 19402950cc38Schristos NSRCADR(&matchaddr) = cr.addr; 19412950cc38Schristos NSRCADR(&matchmask) = cr.mask; 1942abb0f93cSkardel } 1943eabc0478Schristos success = hack_restrict(op, &matchaddr, &matchmask, 1944eabc0478Schristos cr.ippeerlimit, cr.mflags, 1945eabc0478Schristos cr.flags, 0); 1946eabc0478Schristos if (!success) { 1947eabc0478Schristos DPRINTF(1, ("%s: %s %s mask %s ippeerlimit %hd %s %s failed", 1948eabc0478Schristos __func__, resop_str(op), 1949eabc0478Schristos stoa(&matchaddr), stoa(&matchmask), 1950eabc0478Schristos cr.ippeerlimit, mflags_str(cr.mflags), 1951eabc0478Schristos rflags_str(cr.flags))); 1952eabc0478Schristos } 19532950cc38Schristos datap += item_sz; 1954abb0f93cSkardel } 1955abb0f93cSkardel 1956abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 1957abb0f93cSkardel } 1958abb0f93cSkardel 1959abb0f93cSkardel 1960abb0f93cSkardel /* 1961abb0f93cSkardel * mon_getlist - return monitor data 1962abb0f93cSkardel */ 1963abb0f93cSkardel static void 19642950cc38Schristos mon_getlist( 1965abb0f93cSkardel sockaddr_u *srcadr, 19662950cc38Schristos endpt *inter, 1967abb0f93cSkardel struct req_pkt *inpkt 1968abb0f93cSkardel ) 1969abb0f93cSkardel { 1970abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 1971abb0f93cSkardel } 1972abb0f93cSkardel 1973abb0f93cSkardel 1974abb0f93cSkardel /* 1975abb0f93cSkardel * Module entry points and the flags they correspond with 1976abb0f93cSkardel */ 1977abb0f93cSkardel struct reset_entry { 1978abb0f93cSkardel int flag; /* flag this corresponds to */ 1979abb0f93cSkardel void (*handler)(void); /* routine to handle request */ 1980abb0f93cSkardel }; 1981abb0f93cSkardel 1982abb0f93cSkardel struct reset_entry reset_entries[] = { 1983abb0f93cSkardel { RESET_FLAG_ALLPEERS, peer_all_reset }, 1984abb0f93cSkardel { RESET_FLAG_IO, io_clr_stats }, 1985abb0f93cSkardel { RESET_FLAG_SYS, proto_clr_stats }, 1986abb0f93cSkardel { RESET_FLAG_MEM, peer_clr_stats }, 1987abb0f93cSkardel { RESET_FLAG_TIMER, timer_clr_stats }, 1988abb0f93cSkardel { RESET_FLAG_AUTH, reset_auth_stats }, 1989abb0f93cSkardel { RESET_FLAG_CTL, ctl_clr_stats }, 1990abb0f93cSkardel { 0, 0 } 1991abb0f93cSkardel }; 1992abb0f93cSkardel 1993abb0f93cSkardel /* 1994abb0f93cSkardel * reset_stats - reset statistic counters here and there 1995abb0f93cSkardel */ 1996abb0f93cSkardel static void 1997abb0f93cSkardel reset_stats( 1998abb0f93cSkardel sockaddr_u *srcadr, 19992950cc38Schristos endpt *inter, 2000abb0f93cSkardel struct req_pkt *inpkt 2001abb0f93cSkardel ) 2002abb0f93cSkardel { 20033123f114Skardel struct reset_flags *rflags; 2004abb0f93cSkardel u_long flags; 2005abb0f93cSkardel struct reset_entry *rent; 2006abb0f93cSkardel 2007abb0f93cSkardel if (INFO_NITEMS(inpkt->err_nitems) > 1) { 2008abb0f93cSkardel msyslog(LOG_ERR, "reset_stats: err_nitems > 1"); 2009abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 2010abb0f93cSkardel return; 2011abb0f93cSkardel } 2012abb0f93cSkardel 20132950cc38Schristos rflags = (struct reset_flags *)&inpkt->u; 20143123f114Skardel flags = ntohl(rflags->flags); 2015abb0f93cSkardel 2016abb0f93cSkardel if (flags & ~RESET_ALLFLAGS) { 2017abb0f93cSkardel msyslog(LOG_ERR, "reset_stats: reset leaves %#lx", 2018abb0f93cSkardel flags & ~RESET_ALLFLAGS); 2019abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 2020abb0f93cSkardel return; 2021abb0f93cSkardel } 2022abb0f93cSkardel 2023abb0f93cSkardel for (rent = reset_entries; rent->flag != 0; rent++) { 2024abb0f93cSkardel if (flags & rent->flag) 20253123f114Skardel (*rent->handler)(); 2026abb0f93cSkardel } 2027abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2028abb0f93cSkardel } 2029abb0f93cSkardel 2030abb0f93cSkardel 2031abb0f93cSkardel /* 2032abb0f93cSkardel * reset_peer - clear a peer's statistics 2033abb0f93cSkardel */ 2034abb0f93cSkardel static void 2035abb0f93cSkardel reset_peer( 2036abb0f93cSkardel sockaddr_u *srcadr, 20372950cc38Schristos endpt *inter, 2038abb0f93cSkardel struct req_pkt *inpkt 2039abb0f93cSkardel ) 2040abb0f93cSkardel { 20412950cc38Schristos u_short items; 20422950cc38Schristos size_t item_sz; 20432950cc38Schristos char * datap; 20442950cc38Schristos struct conf_unpeer cp; 20452950cc38Schristos struct peer * p; 2046abb0f93cSkardel sockaddr_u peeraddr; 2047abb0f93cSkardel int bad; 2048abb0f93cSkardel 2049abb0f93cSkardel /* 2050abb0f93cSkardel * We check first to see that every peer exists. If not, 2051abb0f93cSkardel * we return an error. 2052abb0f93cSkardel */ 2053abb0f93cSkardel 2054abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 20552950cc38Schristos item_sz = INFO_ITEMSIZE(inpkt->mbz_itemsize); 20562950cc38Schristos datap = inpkt->u.data; 20572950cc38Schristos if (item_sz > sizeof(cp)) { 20582950cc38Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 20592950cc38Schristos return; 20602950cc38Schristos } 2061abb0f93cSkardel 20622950cc38Schristos bad = FALSE; 2063abb0f93cSkardel while (items-- > 0 && !bad) { 20642950cc38Schristos ZERO(cp); 20652950cc38Schristos memcpy(&cp, datap, item_sz); 2066abb0f93cSkardel ZERO_SOCK(&peeraddr); 20672950cc38Schristos if (client_v6_capable && cp.v6_flag) { 2068abb0f93cSkardel AF(&peeraddr) = AF_INET6; 20692950cc38Schristos SOCK_ADDR6(&peeraddr) = cp.peeraddr6; 2070abb0f93cSkardel } else { 2071abb0f93cSkardel AF(&peeraddr) = AF_INET; 20722950cc38Schristos NSRCADR(&peeraddr) = cp.peeraddr; 2073abb0f93cSkardel } 2074abb0f93cSkardel 2075abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 20763123f114Skardel peeraddr.sa.sa_len = SOCKLEN(&peeraddr); 2077abb0f93cSkardel #endif 20784eea345dSchristos p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL); 20792950cc38Schristos if (NULL == p) 2080abb0f93cSkardel bad++; 20812950cc38Schristos datap += item_sz; 2082abb0f93cSkardel } 2083abb0f93cSkardel 2084abb0f93cSkardel if (bad) { 2085abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2086abb0f93cSkardel return; 2087abb0f93cSkardel } 2088abb0f93cSkardel 2089abb0f93cSkardel /* 2090af12ab5eSchristos * Now do it in earnest. Needs to reload data pointer and item 2091af12ab5eSchristos * counter. (Talos-CAN-0052) 2092abb0f93cSkardel */ 2093abb0f93cSkardel 2094af12ab5eSchristos items = INFO_NITEMS(inpkt->err_nitems); 20952950cc38Schristos datap = inpkt->u.data; 2096abb0f93cSkardel while (items-- > 0) { 20972950cc38Schristos ZERO(cp); 20982950cc38Schristos memcpy(&cp, datap, item_sz); 2099abb0f93cSkardel ZERO_SOCK(&peeraddr); 21002950cc38Schristos if (client_v6_capable && cp.v6_flag) { 2101abb0f93cSkardel AF(&peeraddr) = AF_INET6; 21022950cc38Schristos SOCK_ADDR6(&peeraddr) = cp.peeraddr6; 2103abb0f93cSkardel } else { 2104abb0f93cSkardel AF(&peeraddr) = AF_INET; 21052950cc38Schristos NSRCADR(&peeraddr) = cp.peeraddr; 2106abb0f93cSkardel } 2107abb0f93cSkardel SET_PORT(&peeraddr, 123); 2108abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 21093123f114Skardel peeraddr.sa.sa_len = SOCKLEN(&peeraddr); 2110abb0f93cSkardel #endif 21114eea345dSchristos p = findexistingpeer(&peeraddr, NULL, NULL, -1, 0, NULL); 21122950cc38Schristos while (p != NULL) { 21132950cc38Schristos peer_reset(p); 21144eea345dSchristos p = findexistingpeer(&peeraddr, NULL, p, -1, 0, NULL); 2115abb0f93cSkardel } 21162950cc38Schristos datap += item_sz; 2117abb0f93cSkardel } 2118abb0f93cSkardel 2119abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2120abb0f93cSkardel } 2121abb0f93cSkardel 2122abb0f93cSkardel 2123abb0f93cSkardel /* 2124abb0f93cSkardel * do_key_reread - reread the encryption key file 2125abb0f93cSkardel */ 2126abb0f93cSkardel static void 2127abb0f93cSkardel do_key_reread( 2128abb0f93cSkardel sockaddr_u *srcadr, 21292950cc38Schristos endpt *inter, 2130abb0f93cSkardel struct req_pkt *inpkt 2131abb0f93cSkardel ) 2132abb0f93cSkardel { 2133abb0f93cSkardel rereadkeys(); 2134abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2135abb0f93cSkardel } 2136abb0f93cSkardel 2137abb0f93cSkardel 2138abb0f93cSkardel /* 2139abb0f93cSkardel * trust_key - make one or more keys trusted 2140abb0f93cSkardel */ 2141abb0f93cSkardel static void 2142abb0f93cSkardel trust_key( 2143abb0f93cSkardel sockaddr_u *srcadr, 21442950cc38Schristos endpt *inter, 2145abb0f93cSkardel struct req_pkt *inpkt 2146abb0f93cSkardel ) 2147abb0f93cSkardel { 2148abb0f93cSkardel do_trustkey(srcadr, inter, inpkt, 1); 2149abb0f93cSkardel } 2150abb0f93cSkardel 2151abb0f93cSkardel 2152abb0f93cSkardel /* 2153abb0f93cSkardel * untrust_key - make one or more keys untrusted 2154abb0f93cSkardel */ 2155abb0f93cSkardel static void 2156abb0f93cSkardel untrust_key( 2157abb0f93cSkardel sockaddr_u *srcadr, 21582950cc38Schristos endpt *inter, 2159abb0f93cSkardel struct req_pkt *inpkt 2160abb0f93cSkardel ) 2161abb0f93cSkardel { 2162abb0f93cSkardel do_trustkey(srcadr, inter, inpkt, 0); 2163abb0f93cSkardel } 2164abb0f93cSkardel 2165abb0f93cSkardel 2166abb0f93cSkardel /* 2167abb0f93cSkardel * do_trustkey - make keys either trustable or untrustable 2168abb0f93cSkardel */ 2169abb0f93cSkardel static void 2170abb0f93cSkardel do_trustkey( 2171abb0f93cSkardel sockaddr_u *srcadr, 21722950cc38Schristos endpt *inter, 2173abb0f93cSkardel struct req_pkt *inpkt, 2174abb0f93cSkardel u_long trust 2175abb0f93cSkardel ) 2176abb0f93cSkardel { 21778b8da087Schristos register uint32_t *kp; 2178abb0f93cSkardel register int items; 2179abb0f93cSkardel 2180abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 21818b8da087Schristos kp = (uint32_t *)&inpkt->u; 2182abb0f93cSkardel while (items-- > 0) { 2183abb0f93cSkardel authtrust(*kp, trust); 2184abb0f93cSkardel kp++; 2185abb0f93cSkardel } 2186abb0f93cSkardel 2187abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2188abb0f93cSkardel } 2189abb0f93cSkardel 2190abb0f93cSkardel 2191abb0f93cSkardel /* 2192abb0f93cSkardel * get_auth_info - return some stats concerning the authentication module 2193abb0f93cSkardel */ 2194abb0f93cSkardel static void 2195abb0f93cSkardel get_auth_info( 2196abb0f93cSkardel sockaddr_u *srcadr, 21972950cc38Schristos endpt *inter, 2198abb0f93cSkardel struct req_pkt *inpkt 2199abb0f93cSkardel ) 2200abb0f93cSkardel { 2201abb0f93cSkardel register struct info_auth *ia; 2202abb0f93cSkardel 2203abb0f93cSkardel ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt, 2204abb0f93cSkardel sizeof(struct info_auth)); 2205abb0f93cSkardel 2206abb0f93cSkardel ia->numkeys = htonl((u_int32)authnumkeys); 2207abb0f93cSkardel ia->numfreekeys = htonl((u_int32)authnumfreekeys); 2208abb0f93cSkardel ia->keylookups = htonl((u_int32)authkeylookups); 2209abb0f93cSkardel ia->keynotfound = htonl((u_int32)authkeynotfound); 2210abb0f93cSkardel ia->encryptions = htonl((u_int32)authencryptions); 2211abb0f93cSkardel ia->decryptions = htonl((u_int32)authdecryptions); 2212abb0f93cSkardel ia->keyuncached = htonl((u_int32)authkeyuncached); 2213abb0f93cSkardel ia->expired = htonl((u_int32)authkeyexpired); 2214abb0f93cSkardel ia->timereset = htonl((u_int32)(current_time - auth_timereset)); 2215abb0f93cSkardel 2216abb0f93cSkardel (void) more_pkt(); 2217abb0f93cSkardel flush_pkt(); 2218abb0f93cSkardel } 2219abb0f93cSkardel 2220abb0f93cSkardel 2221abb0f93cSkardel 2222abb0f93cSkardel /* 2223abb0f93cSkardel * reset_auth_stats - reset the authentication stat counters. Done here 2224abb0f93cSkardel * to keep ntp-isms out of the authentication module 2225abb0f93cSkardel */ 22262950cc38Schristos void 2227abb0f93cSkardel reset_auth_stats(void) 2228abb0f93cSkardel { 2229abb0f93cSkardel authkeylookups = 0; 2230abb0f93cSkardel authkeynotfound = 0; 2231abb0f93cSkardel authencryptions = 0; 2232abb0f93cSkardel authdecryptions = 0; 2233abb0f93cSkardel authkeyuncached = 0; 2234abb0f93cSkardel auth_timereset = current_time; 2235abb0f93cSkardel } 2236abb0f93cSkardel 2237abb0f93cSkardel 2238abb0f93cSkardel /* 2239abb0f93cSkardel * req_get_traps - return information about current trap holders 2240abb0f93cSkardel */ 2241abb0f93cSkardel static void 2242abb0f93cSkardel req_get_traps( 2243abb0f93cSkardel sockaddr_u *srcadr, 22442950cc38Schristos endpt *inter, 2245abb0f93cSkardel struct req_pkt *inpkt 2246abb0f93cSkardel ) 2247abb0f93cSkardel { 22482950cc38Schristos struct info_trap *it; 22492950cc38Schristos struct ctl_trap *tr; 22502950cc38Schristos size_t i; 2251abb0f93cSkardel 2252abb0f93cSkardel if (num_ctl_traps == 0) { 2253abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2254abb0f93cSkardel return; 2255abb0f93cSkardel } 2256abb0f93cSkardel 2257abb0f93cSkardel it = (struct info_trap *)prepare_pkt(srcadr, inter, inpkt, 2258abb0f93cSkardel v6sizeof(struct info_trap)); 2259abb0f93cSkardel 226068dbbb44Schristos for (i = 0, tr = ctl_traps; it && i < COUNTOF(ctl_traps); i++, tr++) { 2261abb0f93cSkardel if (tr->tr_flags & TRAP_INUSE) { 2262abb0f93cSkardel if (IS_IPV4(&tr->tr_addr)) { 2263abb0f93cSkardel if (tr->tr_localaddr == any_interface) 2264abb0f93cSkardel it->local_address = 0; 2265abb0f93cSkardel else 2266abb0f93cSkardel it->local_address 2267abb0f93cSkardel = NSRCADR(&tr->tr_localaddr->sin); 2268abb0f93cSkardel it->trap_address = NSRCADR(&tr->tr_addr); 2269abb0f93cSkardel if (client_v6_capable) 2270abb0f93cSkardel it->v6_flag = 0; 2271abb0f93cSkardel } else { 2272abb0f93cSkardel if (!client_v6_capable) 2273abb0f93cSkardel continue; 2274abb0f93cSkardel it->local_address6 2275abb0f93cSkardel = SOCK_ADDR6(&tr->tr_localaddr->sin); 2276abb0f93cSkardel it->trap_address6 = SOCK_ADDR6(&tr->tr_addr); 2277abb0f93cSkardel it->v6_flag = 1; 2278abb0f93cSkardel } 2279abb0f93cSkardel it->trap_port = NSRCPORT(&tr->tr_addr); 2280abb0f93cSkardel it->sequence = htons(tr->tr_sequence); 2281abb0f93cSkardel it->settime = htonl((u_int32)(current_time - tr->tr_settime)); 2282abb0f93cSkardel it->origtime = htonl((u_int32)(current_time - tr->tr_origtime)); 2283abb0f93cSkardel it->resets = htonl((u_int32)tr->tr_resets); 2284abb0f93cSkardel it->flags = htonl((u_int32)tr->tr_flags); 2285abb0f93cSkardel it = (struct info_trap *)more_pkt(); 2286abb0f93cSkardel } 2287abb0f93cSkardel } 2288abb0f93cSkardel flush_pkt(); 2289abb0f93cSkardel } 2290abb0f93cSkardel 2291abb0f93cSkardel 2292abb0f93cSkardel /* 2293abb0f93cSkardel * req_set_trap - configure a trap 2294abb0f93cSkardel */ 2295abb0f93cSkardel static void 2296abb0f93cSkardel req_set_trap( 2297abb0f93cSkardel sockaddr_u *srcadr, 22982950cc38Schristos endpt *inter, 2299abb0f93cSkardel struct req_pkt *inpkt 2300abb0f93cSkardel ) 2301abb0f93cSkardel { 2302abb0f93cSkardel do_setclr_trap(srcadr, inter, inpkt, 1); 2303abb0f93cSkardel } 2304abb0f93cSkardel 2305abb0f93cSkardel 2306abb0f93cSkardel 2307abb0f93cSkardel /* 2308abb0f93cSkardel * req_clr_trap - unconfigure a trap 2309abb0f93cSkardel */ 2310abb0f93cSkardel static void 2311abb0f93cSkardel req_clr_trap( 2312abb0f93cSkardel sockaddr_u *srcadr, 23132950cc38Schristos endpt *inter, 2314abb0f93cSkardel struct req_pkt *inpkt 2315abb0f93cSkardel ) 2316abb0f93cSkardel { 2317abb0f93cSkardel do_setclr_trap(srcadr, inter, inpkt, 0); 2318abb0f93cSkardel } 2319abb0f93cSkardel 2320abb0f93cSkardel 2321abb0f93cSkardel 2322abb0f93cSkardel /* 2323abb0f93cSkardel * do_setclr_trap - do the grunge work of (un)configuring a trap 2324abb0f93cSkardel */ 2325abb0f93cSkardel static void 2326abb0f93cSkardel do_setclr_trap( 2327abb0f93cSkardel sockaddr_u *srcadr, 23282950cc38Schristos endpt *inter, 2329abb0f93cSkardel struct req_pkt *inpkt, 2330abb0f93cSkardel int set 2331abb0f93cSkardel ) 2332abb0f93cSkardel { 2333abb0f93cSkardel register struct conf_trap *ct; 23342950cc38Schristos register endpt *linter; 2335abb0f93cSkardel int res; 2336abb0f93cSkardel sockaddr_u laddr; 2337abb0f93cSkardel 2338abb0f93cSkardel /* 2339abb0f93cSkardel * Prepare sockaddr 2340abb0f93cSkardel */ 2341abb0f93cSkardel ZERO_SOCK(&laddr); 2342abb0f93cSkardel AF(&laddr) = AF(srcadr); 2343abb0f93cSkardel SET_PORT(&laddr, NTP_PORT); 2344abb0f93cSkardel 2345abb0f93cSkardel /* 2346abb0f93cSkardel * Restrict ourselves to one item only. This eliminates 2347abb0f93cSkardel * the error reporting problem. 2348abb0f93cSkardel */ 2349abb0f93cSkardel if (INFO_NITEMS(inpkt->err_nitems) > 1) { 2350abb0f93cSkardel msyslog(LOG_ERR, "do_setclr_trap: err_nitems > 1"); 2351abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 2352abb0f93cSkardel return; 2353abb0f93cSkardel } 23542950cc38Schristos ct = (struct conf_trap *)&inpkt->u; 2355abb0f93cSkardel 2356abb0f93cSkardel /* 2357abb0f93cSkardel * Look for the local interface. If none, use the default. 2358abb0f93cSkardel */ 2359abb0f93cSkardel if (ct->local_address == 0) { 2360abb0f93cSkardel linter = any_interface; 2361abb0f93cSkardel } else { 2362abb0f93cSkardel if (IS_IPV4(&laddr)) 2363abb0f93cSkardel NSRCADR(&laddr) = ct->local_address; 2364abb0f93cSkardel else 2365abb0f93cSkardel SOCK_ADDR6(&laddr) = ct->local_address6; 2366abb0f93cSkardel linter = findinterface(&laddr); 2367abb0f93cSkardel if (NULL == linter) { 2368abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2369abb0f93cSkardel return; 2370abb0f93cSkardel } 2371abb0f93cSkardel } 2372abb0f93cSkardel 2373abb0f93cSkardel if (IS_IPV4(&laddr)) 2374abb0f93cSkardel NSRCADR(&laddr) = ct->trap_address; 2375abb0f93cSkardel else 2376abb0f93cSkardel SOCK_ADDR6(&laddr) = ct->trap_address6; 2377abb0f93cSkardel if (ct->trap_port) 2378abb0f93cSkardel NSRCPORT(&laddr) = ct->trap_port; 2379abb0f93cSkardel else 2380abb0f93cSkardel SET_PORT(&laddr, TRAPPORT); 2381abb0f93cSkardel 2382abb0f93cSkardel if (set) { 2383abb0f93cSkardel res = ctlsettrap(&laddr, linter, 0, 2384abb0f93cSkardel INFO_VERSION(inpkt->rm_vn_mode)); 2385abb0f93cSkardel } else { 2386abb0f93cSkardel res = ctlclrtrap(&laddr, linter, 0); 2387abb0f93cSkardel } 2388abb0f93cSkardel 2389abb0f93cSkardel if (!res) { 2390abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2391abb0f93cSkardel } else { 2392abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2393abb0f93cSkardel } 2394abb0f93cSkardel return; 2395abb0f93cSkardel } 2396abb0f93cSkardel 239768dbbb44Schristos /* 239868dbbb44Schristos * Validate a request packet for a new request or control key: 239968dbbb44Schristos * - only one item allowed 240068dbbb44Schristos * - key must be valid (that is, known, and not in the autokey range) 240168dbbb44Schristos */ 240268dbbb44Schristos static void 240368dbbb44Schristos set_keyid_checked( 240468dbbb44Schristos keyid_t *into, 240568dbbb44Schristos const char *what, 240668dbbb44Schristos sockaddr_u *srcadr, 240768dbbb44Schristos endpt *inter, 240868dbbb44Schristos struct req_pkt *inpkt 240968dbbb44Schristos ) 241068dbbb44Schristos { 241168dbbb44Schristos keyid_t *pkeyid; 241268dbbb44Schristos keyid_t tmpkey; 2413abb0f93cSkardel 241468dbbb44Schristos /* restrict ourselves to one item only */ 241568dbbb44Schristos if (INFO_NITEMS(inpkt->err_nitems) > 1) { 241668dbbb44Schristos msyslog(LOG_ERR, "set_keyid_checked[%s]: err_nitems > 1", 241768dbbb44Schristos what); 241868dbbb44Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 241968dbbb44Schristos return; 242068dbbb44Schristos } 242168dbbb44Schristos 242268dbbb44Schristos /* plug the new key from the packet */ 242368dbbb44Schristos pkeyid = (keyid_t *)&inpkt->u; 242468dbbb44Schristos tmpkey = ntohl(*pkeyid); 242568dbbb44Schristos 242668dbbb44Schristos /* validate the new key id, claim data error on failure */ 242768dbbb44Schristos if (tmpkey < 1 || tmpkey > NTP_MAXKEY || !auth_havekey(tmpkey)) { 242868dbbb44Schristos msyslog(LOG_ERR, "set_keyid_checked[%s]: invalid key id: %ld", 242968dbbb44Schristos what, (long)tmpkey); 243068dbbb44Schristos req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 243168dbbb44Schristos return; 243268dbbb44Schristos } 243368dbbb44Schristos 243468dbbb44Schristos /* if we arrive here, the key is good -- use it */ 243568dbbb44Schristos *into = tmpkey; 243668dbbb44Schristos req_ack(srcadr, inter, inpkt, INFO_OKAY); 243768dbbb44Schristos } 2438abb0f93cSkardel 2439abb0f93cSkardel /* 2440abb0f93cSkardel * set_request_keyid - set the keyid used to authenticate requests 2441abb0f93cSkardel */ 2442abb0f93cSkardel static void 2443abb0f93cSkardel set_request_keyid( 2444abb0f93cSkardel sockaddr_u *srcadr, 24452950cc38Schristos endpt *inter, 2446abb0f93cSkardel struct req_pkt *inpkt 2447abb0f93cSkardel ) 2448abb0f93cSkardel { 244968dbbb44Schristos set_keyid_checked(&info_auth_keyid, "request", 245068dbbb44Schristos srcadr, inter, inpkt); 2451abb0f93cSkardel } 2452abb0f93cSkardel 2453abb0f93cSkardel 2454abb0f93cSkardel 2455abb0f93cSkardel /* 2456abb0f93cSkardel * set_control_keyid - set the keyid used to authenticate requests 2457abb0f93cSkardel */ 2458abb0f93cSkardel static void 2459abb0f93cSkardel set_control_keyid( 2460abb0f93cSkardel sockaddr_u *srcadr, 24612950cc38Schristos endpt *inter, 2462abb0f93cSkardel struct req_pkt *inpkt 2463abb0f93cSkardel ) 2464abb0f93cSkardel { 246568dbbb44Schristos set_keyid_checked(&ctl_auth_keyid, "control", 246668dbbb44Schristos srcadr, inter, inpkt); 2467abb0f93cSkardel } 2468abb0f93cSkardel 2469abb0f93cSkardel 2470abb0f93cSkardel 2471abb0f93cSkardel /* 2472abb0f93cSkardel * get_ctl_stats - return some stats concerning the control message module 2473abb0f93cSkardel */ 2474abb0f93cSkardel static void 2475abb0f93cSkardel get_ctl_stats( 2476abb0f93cSkardel sockaddr_u *srcadr, 24772950cc38Schristos endpt *inter, 2478abb0f93cSkardel struct req_pkt *inpkt 2479abb0f93cSkardel ) 2480abb0f93cSkardel { 2481abb0f93cSkardel register struct info_control *ic; 2482abb0f93cSkardel 2483abb0f93cSkardel ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt, 2484abb0f93cSkardel sizeof(struct info_control)); 2485abb0f93cSkardel 2486abb0f93cSkardel ic->ctltimereset = htonl((u_int32)(current_time - ctltimereset)); 2487abb0f93cSkardel ic->numctlreq = htonl((u_int32)numctlreq); 2488abb0f93cSkardel ic->numctlbadpkts = htonl((u_int32)numctlbadpkts); 2489abb0f93cSkardel ic->numctlresponses = htonl((u_int32)numctlresponses); 2490abb0f93cSkardel ic->numctlfrags = htonl((u_int32)numctlfrags); 2491abb0f93cSkardel ic->numctlerrors = htonl((u_int32)numctlerrors); 2492abb0f93cSkardel ic->numctltooshort = htonl((u_int32)numctltooshort); 2493abb0f93cSkardel ic->numctlinputresp = htonl((u_int32)numctlinputresp); 2494abb0f93cSkardel ic->numctlinputfrag = htonl((u_int32)numctlinputfrag); 2495abb0f93cSkardel ic->numctlinputerr = htonl((u_int32)numctlinputerr); 2496abb0f93cSkardel ic->numctlbadoffset = htonl((u_int32)numctlbadoffset); 2497abb0f93cSkardel ic->numctlbadversion = htonl((u_int32)numctlbadversion); 2498abb0f93cSkardel ic->numctldatatooshort = htonl((u_int32)numctldatatooshort); 2499abb0f93cSkardel ic->numctlbadop = htonl((u_int32)numctlbadop); 2500abb0f93cSkardel ic->numasyncmsgs = htonl((u_int32)numasyncmsgs); 2501abb0f93cSkardel 2502abb0f93cSkardel (void) more_pkt(); 2503abb0f93cSkardel flush_pkt(); 2504abb0f93cSkardel } 2505abb0f93cSkardel 2506abb0f93cSkardel 2507abb0f93cSkardel #ifdef KERNEL_PLL 2508abb0f93cSkardel /* 2509abb0f93cSkardel * get_kernel_info - get kernel pll/pps information 2510abb0f93cSkardel */ 2511abb0f93cSkardel static void 2512abb0f93cSkardel get_kernel_info( 2513abb0f93cSkardel sockaddr_u *srcadr, 25142950cc38Schristos endpt *inter, 2515abb0f93cSkardel struct req_pkt *inpkt 2516abb0f93cSkardel ) 2517abb0f93cSkardel { 2518abb0f93cSkardel register struct info_kernel *ik; 2519abb0f93cSkardel struct timex ntx; 2520abb0f93cSkardel 2521abb0f93cSkardel if (!pll_control) { 2522abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2523abb0f93cSkardel return; 2524abb0f93cSkardel } 2525abb0f93cSkardel 25262950cc38Schristos ZERO(ntx); 2527abb0f93cSkardel if (ntp_adjtime(&ntx) < 0) 2528abb0f93cSkardel msyslog(LOG_ERR, "get_kernel_info: ntp_adjtime() failed: %m"); 2529abb0f93cSkardel ik = (struct info_kernel *)prepare_pkt(srcadr, inter, inpkt, 2530abb0f93cSkardel sizeof(struct info_kernel)); 2531abb0f93cSkardel 2532abb0f93cSkardel /* 2533abb0f93cSkardel * pll variables 2534abb0f93cSkardel */ 2535abb0f93cSkardel ik->offset = htonl((u_int32)ntx.offset); 2536abb0f93cSkardel ik->freq = htonl((u_int32)ntx.freq); 2537abb0f93cSkardel ik->maxerror = htonl((u_int32)ntx.maxerror); 2538abb0f93cSkardel ik->esterror = htonl((u_int32)ntx.esterror); 2539abb0f93cSkardel ik->status = htons(ntx.status); 2540abb0f93cSkardel ik->constant = htonl((u_int32)ntx.constant); 2541abb0f93cSkardel ik->precision = htonl((u_int32)ntx.precision); 2542abb0f93cSkardel ik->tolerance = htonl((u_int32)ntx.tolerance); 2543abb0f93cSkardel 2544abb0f93cSkardel /* 2545abb0f93cSkardel * pps variables 2546abb0f93cSkardel */ 2547abb0f93cSkardel ik->ppsfreq = htonl((u_int32)ntx.ppsfreq); 2548abb0f93cSkardel ik->jitter = htonl((u_int32)ntx.jitter); 2549abb0f93cSkardel ik->shift = htons(ntx.shift); 2550abb0f93cSkardel ik->stabil = htonl((u_int32)ntx.stabil); 2551abb0f93cSkardel ik->jitcnt = htonl((u_int32)ntx.jitcnt); 2552abb0f93cSkardel ik->calcnt = htonl((u_int32)ntx.calcnt); 2553abb0f93cSkardel ik->errcnt = htonl((u_int32)ntx.errcnt); 2554abb0f93cSkardel ik->stbcnt = htonl((u_int32)ntx.stbcnt); 2555abb0f93cSkardel 2556abb0f93cSkardel (void) more_pkt(); 2557abb0f93cSkardel flush_pkt(); 2558abb0f93cSkardel } 2559abb0f93cSkardel #endif /* KERNEL_PLL */ 2560abb0f93cSkardel 2561abb0f93cSkardel 2562abb0f93cSkardel #ifdef REFCLOCK 2563abb0f93cSkardel /* 2564abb0f93cSkardel * get_clock_info - get info about a clock 2565abb0f93cSkardel */ 2566abb0f93cSkardel static void 2567abb0f93cSkardel get_clock_info( 2568abb0f93cSkardel sockaddr_u *srcadr, 25692950cc38Schristos endpt *inter, 2570abb0f93cSkardel struct req_pkt *inpkt 2571abb0f93cSkardel ) 2572abb0f93cSkardel { 2573abb0f93cSkardel register struct info_clock *ic; 2574abb0f93cSkardel register u_int32 *clkaddr; 2575abb0f93cSkardel register int items; 2576abb0f93cSkardel struct refclockstat clock_stat; 2577abb0f93cSkardel sockaddr_u addr; 2578abb0f93cSkardel l_fp ltmp; 2579abb0f93cSkardel 2580abb0f93cSkardel ZERO_SOCK(&addr); 2581abb0f93cSkardel AF(&addr) = AF_INET; 2582abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 25833123f114Skardel addr.sa.sa_len = SOCKLEN(&addr); 2584abb0f93cSkardel #endif 2585abb0f93cSkardel SET_PORT(&addr, NTP_PORT); 2586abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 25872950cc38Schristos clkaddr = &inpkt->u.u32[0]; 2588abb0f93cSkardel 2589abb0f93cSkardel ic = (struct info_clock *)prepare_pkt(srcadr, inter, inpkt, 2590abb0f93cSkardel sizeof(struct info_clock)); 2591abb0f93cSkardel 259268dbbb44Schristos while (items-- > 0 && ic) { 2593abb0f93cSkardel NSRCADR(&addr) = *clkaddr++; 25942950cc38Schristos if (!ISREFCLOCKADR(&addr) || NULL == 25954eea345dSchristos findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) { 2596abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2597abb0f93cSkardel return; 2598abb0f93cSkardel } 2599abb0f93cSkardel 2600abb0f93cSkardel clock_stat.kv_list = (struct ctl_var *)0; 2601abb0f93cSkardel 2602abb0f93cSkardel refclock_control(&addr, NULL, &clock_stat); 2603abb0f93cSkardel 2604abb0f93cSkardel ic->clockadr = NSRCADR(&addr); 2605abb0f93cSkardel ic->type = clock_stat.type; 2606abb0f93cSkardel ic->flags = clock_stat.flags; 2607abb0f93cSkardel ic->lastevent = clock_stat.lastevent; 2608abb0f93cSkardel ic->currentstatus = clock_stat.currentstatus; 2609abb0f93cSkardel ic->polls = htonl((u_int32)clock_stat.polls); 2610abb0f93cSkardel ic->noresponse = htonl((u_int32)clock_stat.noresponse); 2611abb0f93cSkardel ic->badformat = htonl((u_int32)clock_stat.badformat); 2612abb0f93cSkardel ic->baddata = htonl((u_int32)clock_stat.baddata); 2613abb0f93cSkardel ic->timestarted = htonl((u_int32)clock_stat.timereset); 2614abb0f93cSkardel DTOLFP(clock_stat.fudgetime1, <mp); 2615abb0f93cSkardel HTONL_FP(<mp, &ic->fudgetime1); 2616abb0f93cSkardel DTOLFP(clock_stat.fudgetime2, <mp); 2617abb0f93cSkardel HTONL_FP(<mp, &ic->fudgetime2); 2618abb0f93cSkardel ic->fudgeval1 = htonl((u_int32)clock_stat.fudgeval1); 2619cdfa2a7eSchristos /* [Bug3527] Backward Incompatible: ic->fudgeval2 is 2620cdfa2a7eSchristos * a string, instantiated via memcpy() so there is no 2621cdfa2a7eSchristos * endian issue to correct. 2622cdfa2a7eSchristos */ 2623cdfa2a7eSchristos #ifdef DISABLE_BUG3527_FIX 26243123f114Skardel ic->fudgeval2 = htonl(clock_stat.fudgeval2); 2625cdfa2a7eSchristos #else 2626cdfa2a7eSchristos ic->fudgeval2 = clock_stat.fudgeval2; 2627cdfa2a7eSchristos #endif 2628abb0f93cSkardel 2629abb0f93cSkardel free_varlist(clock_stat.kv_list); 2630abb0f93cSkardel 2631abb0f93cSkardel ic = (struct info_clock *)more_pkt(); 2632abb0f93cSkardel } 2633abb0f93cSkardel flush_pkt(); 2634abb0f93cSkardel } 2635abb0f93cSkardel 2636abb0f93cSkardel 2637abb0f93cSkardel 2638abb0f93cSkardel /* 2639abb0f93cSkardel * set_clock_fudge - get a clock's fudge factors 2640abb0f93cSkardel */ 2641abb0f93cSkardel static void 2642abb0f93cSkardel set_clock_fudge( 2643abb0f93cSkardel sockaddr_u *srcadr, 26442950cc38Schristos endpt *inter, 2645abb0f93cSkardel struct req_pkt *inpkt 2646abb0f93cSkardel ) 2647abb0f93cSkardel { 2648abb0f93cSkardel register struct conf_fudge *cf; 2649abb0f93cSkardel register int items; 2650abb0f93cSkardel struct refclockstat clock_stat; 2651abb0f93cSkardel sockaddr_u addr; 2652abb0f93cSkardel l_fp ltmp; 2653abb0f93cSkardel 26542950cc38Schristos ZERO(addr); 26552950cc38Schristos ZERO(clock_stat); 2656abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 26572950cc38Schristos cf = (struct conf_fudge *)&inpkt->u; 2658abb0f93cSkardel 2659abb0f93cSkardel while (items-- > 0) { 2660abb0f93cSkardel AF(&addr) = AF_INET; 2661abb0f93cSkardel NSRCADR(&addr) = cf->clockadr; 2662abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 26633123f114Skardel addr.sa.sa_len = SOCKLEN(&addr); 2664abb0f93cSkardel #endif 2665abb0f93cSkardel SET_PORT(&addr, NTP_PORT); 26662950cc38Schristos if (!ISREFCLOCKADR(&addr) || NULL == 26674eea345dSchristos findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) { 2668abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2669abb0f93cSkardel return; 2670abb0f93cSkardel } 2671abb0f93cSkardel 2672abb0f93cSkardel switch(ntohl(cf->which)) { 2673abb0f93cSkardel case FUDGE_TIME1: 2674abb0f93cSkardel NTOHL_FP(&cf->fudgetime, <mp); 2675abb0f93cSkardel LFPTOD(<mp, clock_stat.fudgetime1); 2676abb0f93cSkardel clock_stat.haveflags = CLK_HAVETIME1; 2677abb0f93cSkardel break; 2678abb0f93cSkardel case FUDGE_TIME2: 2679abb0f93cSkardel NTOHL_FP(&cf->fudgetime, <mp); 2680abb0f93cSkardel LFPTOD(<mp, clock_stat.fudgetime2); 2681abb0f93cSkardel clock_stat.haveflags = CLK_HAVETIME2; 2682abb0f93cSkardel break; 2683abb0f93cSkardel case FUDGE_VAL1: 2684abb0f93cSkardel clock_stat.fudgeval1 = ntohl(cf->fudgeval_flags); 2685abb0f93cSkardel clock_stat.haveflags = CLK_HAVEVAL1; 2686abb0f93cSkardel break; 2687abb0f93cSkardel case FUDGE_VAL2: 2688abb0f93cSkardel clock_stat.fudgeval2 = ntohl(cf->fudgeval_flags); 2689abb0f93cSkardel clock_stat.haveflags = CLK_HAVEVAL2; 2690abb0f93cSkardel break; 2691abb0f93cSkardel case FUDGE_FLAGS: 2692abb0f93cSkardel clock_stat.flags = (u_char) (ntohl(cf->fudgeval_flags) & 0xf); 2693abb0f93cSkardel clock_stat.haveflags = 2694abb0f93cSkardel (CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4); 2695abb0f93cSkardel break; 2696abb0f93cSkardel default: 2697abb0f93cSkardel msyslog(LOG_ERR, "set_clock_fudge: default!"); 2698abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_FMT); 2699abb0f93cSkardel return; 2700abb0f93cSkardel } 2701abb0f93cSkardel 2702abb0f93cSkardel refclock_control(&addr, &clock_stat, (struct refclockstat *)0); 2703abb0f93cSkardel } 2704abb0f93cSkardel 2705abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_OKAY); 2706abb0f93cSkardel } 2707abb0f93cSkardel #endif 2708abb0f93cSkardel 2709abb0f93cSkardel #ifdef REFCLOCK 2710abb0f93cSkardel /* 2711abb0f93cSkardel * get_clkbug_info - get debugging info about a clock 2712abb0f93cSkardel */ 2713abb0f93cSkardel static void 2714abb0f93cSkardel get_clkbug_info( 2715abb0f93cSkardel sockaddr_u *srcadr, 27162950cc38Schristos endpt *inter, 2717abb0f93cSkardel struct req_pkt *inpkt 2718abb0f93cSkardel ) 2719abb0f93cSkardel { 2720abb0f93cSkardel register int i; 2721abb0f93cSkardel register struct info_clkbug *ic; 2722abb0f93cSkardel register u_int32 *clkaddr; 2723abb0f93cSkardel register int items; 2724abb0f93cSkardel struct refclockbug bug; 2725abb0f93cSkardel sockaddr_u addr; 2726abb0f93cSkardel 2727abb0f93cSkardel ZERO_SOCK(&addr); 2728abb0f93cSkardel AF(&addr) = AF_INET; 2729abb0f93cSkardel #ifdef ISC_PLATFORM_HAVESALEN 27303123f114Skardel addr.sa.sa_len = SOCKLEN(&addr); 2731abb0f93cSkardel #endif 2732abb0f93cSkardel SET_PORT(&addr, NTP_PORT); 2733abb0f93cSkardel items = INFO_NITEMS(inpkt->err_nitems); 27342950cc38Schristos clkaddr = (u_int32 *)&inpkt->u; 2735abb0f93cSkardel 2736abb0f93cSkardel ic = (struct info_clkbug *)prepare_pkt(srcadr, inter, inpkt, 2737abb0f93cSkardel sizeof(struct info_clkbug)); 2738abb0f93cSkardel 273968dbbb44Schristos while (items-- > 0 && ic) { 2740abb0f93cSkardel NSRCADR(&addr) = *clkaddr++; 27412950cc38Schristos if (!ISREFCLOCKADR(&addr) || NULL == 27424eea345dSchristos findexistingpeer(&addr, NULL, NULL, -1, 0, NULL)) { 2743abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2744abb0f93cSkardel return; 2745abb0f93cSkardel } 2746abb0f93cSkardel 27472950cc38Schristos ZERO(bug); 2748abb0f93cSkardel refclock_buginfo(&addr, &bug); 2749abb0f93cSkardel if (bug.nvalues == 0 && bug.ntimes == 0) { 2750abb0f93cSkardel req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA); 2751abb0f93cSkardel return; 2752abb0f93cSkardel } 2753abb0f93cSkardel 2754abb0f93cSkardel ic->clockadr = NSRCADR(&addr); 2755abb0f93cSkardel i = bug.nvalues; 2756abb0f93cSkardel if (i > NUMCBUGVALUES) 2757abb0f93cSkardel i = NUMCBUGVALUES; 2758abb0f93cSkardel ic->nvalues = (u_char)i; 2759abb0f93cSkardel ic->svalues = htons((u_short) (bug.svalues & ((1<<i)-1))); 2760abb0f93cSkardel while (--i >= 0) 2761abb0f93cSkardel ic->values[i] = htonl(bug.values[i]); 2762abb0f93cSkardel 2763abb0f93cSkardel i = bug.ntimes; 2764abb0f93cSkardel if (i > NUMCBUGTIMES) 2765abb0f93cSkardel i = NUMCBUGTIMES; 2766abb0f93cSkardel ic->ntimes = (u_char)i; 2767abb0f93cSkardel ic->stimes = htonl(bug.stimes); 2768abb0f93cSkardel while (--i >= 0) { 2769abb0f93cSkardel HTONL_FP(&bug.times[i], &ic->times[i]); 2770abb0f93cSkardel } 2771abb0f93cSkardel 2772abb0f93cSkardel ic = (struct info_clkbug *)more_pkt(); 2773abb0f93cSkardel } 2774abb0f93cSkardel flush_pkt(); 2775abb0f93cSkardel } 2776abb0f93cSkardel #endif 2777abb0f93cSkardel 2778abb0f93cSkardel /* 2779abb0f93cSkardel * receiver of interface structures 2780abb0f93cSkardel */ 2781abb0f93cSkardel static void 2782abb0f93cSkardel fill_info_if_stats(void *data, interface_info_t *interface_info) 2783abb0f93cSkardel { 2784abb0f93cSkardel struct info_if_stats **ifsp = (struct info_if_stats **)data; 2785abb0f93cSkardel struct info_if_stats *ifs = *ifsp; 27863123f114Skardel endpt *ep = interface_info->ep; 2787abb0f93cSkardel 278868dbbb44Schristos if (NULL == ifs) 278968dbbb44Schristos return; 279068dbbb44Schristos 27912950cc38Schristos ZERO(*ifs); 2792abb0f93cSkardel 27933123f114Skardel if (IS_IPV6(&ep->sin)) { 279468dbbb44Schristos if (!client_v6_capable) 2795abb0f93cSkardel return; 2796abb0f93cSkardel ifs->v6_flag = 1; 27973123f114Skardel ifs->unaddr.addr6 = SOCK_ADDR6(&ep->sin); 27983123f114Skardel ifs->unbcast.addr6 = SOCK_ADDR6(&ep->bcast); 27993123f114Skardel ifs->unmask.addr6 = SOCK_ADDR6(&ep->mask); 2800abb0f93cSkardel } else { 2801abb0f93cSkardel ifs->v6_flag = 0; 28023123f114Skardel ifs->unaddr.addr = SOCK_ADDR4(&ep->sin); 28033123f114Skardel ifs->unbcast.addr = SOCK_ADDR4(&ep->bcast); 28043123f114Skardel ifs->unmask.addr = SOCK_ADDR4(&ep->mask); 2805abb0f93cSkardel } 2806abb0f93cSkardel ifs->v6_flag = htonl(ifs->v6_flag); 28072950cc38Schristos strlcpy(ifs->name, ep->name, sizeof(ifs->name)); 28083123f114Skardel ifs->family = htons(ep->family); 28093123f114Skardel ifs->flags = htonl(ep->flags); 28103123f114Skardel ifs->last_ttl = htonl(ep->last_ttl); 28113123f114Skardel ifs->num_mcast = htonl(ep->num_mcast); 28123123f114Skardel ifs->received = htonl(ep->received); 28133123f114Skardel ifs->sent = htonl(ep->sent); 28143123f114Skardel ifs->notsent = htonl(ep->notsent); 28153123f114Skardel ifs->ifindex = htonl(ep->ifindex); 28162950cc38Schristos /* scope no longer in endpt, in in6_addr typically */ 28173123f114Skardel ifs->scopeid = ifs->ifindex; 28183123f114Skardel ifs->ifnum = htonl(ep->ifnum); 28193123f114Skardel ifs->uptime = htonl(current_time - ep->starttime); 28203123f114Skardel ifs->ignore_packets = ep->ignore_packets; 28213123f114Skardel ifs->peercnt = htonl(ep->peercnt); 2822abb0f93cSkardel ifs->action = interface_info->action; 2823abb0f93cSkardel 2824abb0f93cSkardel *ifsp = (struct info_if_stats *)more_pkt(); 2825abb0f93cSkardel } 2826abb0f93cSkardel 2827abb0f93cSkardel /* 2828abb0f93cSkardel * get_if_stats - get interface statistics 2829abb0f93cSkardel */ 2830abb0f93cSkardel static void 2831abb0f93cSkardel get_if_stats( 2832abb0f93cSkardel sockaddr_u *srcadr, 28332950cc38Schristos endpt *inter, 2834abb0f93cSkardel struct req_pkt *inpkt 2835abb0f93cSkardel ) 2836abb0f93cSkardel { 2837abb0f93cSkardel struct info_if_stats *ifs; 2838abb0f93cSkardel 2839abb0f93cSkardel DPRINTF(3, ("wants interface statistics\n")); 2840abb0f93cSkardel 2841abb0f93cSkardel ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt, 2842abb0f93cSkardel v6sizeof(struct info_if_stats)); 2843abb0f93cSkardel 2844abb0f93cSkardel interface_enumerate(fill_info_if_stats, &ifs); 2845abb0f93cSkardel 2846abb0f93cSkardel flush_pkt(); 2847abb0f93cSkardel } 2848abb0f93cSkardel 2849abb0f93cSkardel static void 2850abb0f93cSkardel do_if_reload( 2851abb0f93cSkardel sockaddr_u *srcadr, 28522950cc38Schristos endpt *inter, 2853abb0f93cSkardel struct req_pkt *inpkt 2854abb0f93cSkardel ) 2855abb0f93cSkardel { 2856abb0f93cSkardel struct info_if_stats *ifs; 2857abb0f93cSkardel 2858abb0f93cSkardel DPRINTF(3, ("wants interface reload\n")); 2859abb0f93cSkardel 2860abb0f93cSkardel ifs = (struct info_if_stats *)prepare_pkt(srcadr, inter, inpkt, 2861abb0f93cSkardel v6sizeof(struct info_if_stats)); 2862abb0f93cSkardel 2863abb0f93cSkardel interface_update(fill_info_if_stats, &ifs); 2864abb0f93cSkardel 2865abb0f93cSkardel flush_pkt(); 2866abb0f93cSkardel } 2867abb0f93cSkardel 2868