📄 ntpq.c
字号:
* First try to resolve it as an ip address and if that fails, * do a fullblown (dns) lookup. That way we only use the dns * when it is needed and work around some implementations that * will return an "IPv4-mapped IPv6 address" address if you * give it an IPv4 address to lookup. */ strcpy(service, "ntp"); memset((char *)&hints, 0, sizeof(struct addrinfo)); hints.ai_family = ai_fam_templ; hints.ai_protocol = IPPROTO_UDP; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST; a_info = getaddrinfo(hname, service, &hints, &ai); if (a_info == EAI_NONAME#ifdef EAI_NODATA || a_info == EAI_NODATA#endif ) { hints.ai_flags = AI_CANONNAME;#ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG;#endif a_info = getaddrinfo(hname, service, &hints, &ai); } /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags = AI_CANONNAME; a_info = getaddrinfo(hname, service, &hints, &ai); } if (a_info != 0) { (void) fprintf(stderr, "%s\n", gai_strerror(a_info)); return 0; } if (ai->ai_canonname == NULL) { strncpy(temphost, stoa((struct sockaddr_storage *)ai->ai_addr), LENHOSTNAME); temphost[LENHOSTNAME-1] = '\0'; } else { strncpy(temphost, ai->ai_canonname, LENHOSTNAME); temphost[LENHOSTNAME-1] = '\0'; } if (debug > 2) printf("Opening host %s\n", temphost); if (havehost == 1) { if (debug > 2) printf("Closing old host %s\n", currenthost); (void) closesocket(sockfd); havehost = 0; } (void) strcpy(currenthost, temphost); /* port maps to the same location in both families */ s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;#ifdef SYS_VXWORKS ((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM); if (ai->ai_family == AF_INET) *(struct sockaddr_in *)&hostaddr= *((struct sockaddr_in *)ai->ai_addr); else *(struct sockaddr_in6 *)&hostaddr= *((struct sockaddr_in6 *)ai->ai_addr);#endif /* SYS_VXWORKS */#ifdef SYS_WINNT { int optionValue = SO_SYNCHRONOUS_NONALERT; int err; err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue)); if (err != NO_ERROR) { (void) fprintf(stderr, "cannot open nonoverlapped sockets\n"); exit(1); } }#endif /* SYS_WINNT */ sockfd = socket(ai->ai_family, SOCK_DGRAM, 0); if (sockfd == INVALID_SOCKET) { error("socket", "", ""); } #ifdef NEED_RCVBUF_SLOP# ifdef SO_RCVBUF { int rbufsize = DATASIZE + 2048; /* 2K for slop */ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &rbufsize, sizeof(int)) == -1) error("setsockopt", "", ""); }# endif#endif#ifdef SYS_VXWORKS if (connect(sockfd, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) == -1)#else if (connect(sockfd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)#endif /* SYS_VXWORKS */ error("connect", "", ""); if (a_info == 0) freeaddrinfo(ai); havehost = 1; return 1;}/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c *//* * sendpkt - send a packet to the remote host */static intsendpkt( char *xdata, int xdatalen ){ if (debug >= 3) printf("Sending %d octets\n", xdatalen); if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) { warning("write to %s failed", currenthost, ""); return -1; } if (debug >= 4) { int first = 8; printf("Packet data:\n"); while (xdatalen-- > 0) { if (first-- == 0) { printf("\n"); first = 7; } printf(" %02x", *xdata++ & 0xff); } printf("\n"); } return 0;}/* * getresponse - get a (series of) response packet(s) and return the data */static intgetresponse( int opcode, int associd, u_short *rstatus, int *rsize, char **rdata, int timeo ){ struct ntp_control rpkt; struct timeval tvo; u_short offsets[MAXFRAGS+1]; u_short counts[MAXFRAGS+1]; u_short offset; u_short count; int numfrags; int seenlastfrag; fd_set fds; int n; /* * This is pretty tricky. We may get between 1 and MAXFRAG packets * back in response to the request. We peel the data out of * each packet and collect it in one long block. When the last * packet in the sequence is received we'll know how much data we * should have had. Note we use one long time out, should reconsider. */ *rsize = 0; if (rstatus) *rstatus = 0; *rdata = (char *)pktdata; numfrags = 0; seenlastfrag = 0; FD_ZERO(&fds); again: if (numfrags == 0) tvo = tvout; else tvo = tvsout; FD_SET(sockfd, &fds); n = select(sockfd+1, &fds, (fd_set *)0, (fd_set *)0, &tvo);#if 0 if (debug >= 1) printf("select() returns %d\n", n);#endif if (n == -1) { warning("select fails", "", ""); return -1; } if (n == 0) { /* * Timed out. Return what we have */ if (numfrags == 0) { if (timeo) (void) fprintf(stderr, "%s: timed out, nothing received\n", currenthost); return ERR_TIMEOUT; } else { if (timeo) (void) fprintf(stderr, "%s: timed out with incomplete data\n", currenthost); if (debug) { printf("Received fragments:\n"); for (n = 0; n < numfrags; n++) printf("%4d %d\n", offsets[n], counts[n]); if (seenlastfrag) printf("last fragment received\n"); else printf("last fragment not received\n"); } return ERR_INCOMPLETE; } } n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0); if (n == -1) { warning("read", "", ""); return -1; } if (debug >= 4) { int len = n, first = 8; char *data = (char *)&rpkt; printf("Packet data:\n"); while (len-- > 0) { if (first-- == 0) { printf("\n"); first = 7; } printf(" %02x", *data++ & 0xff); } printf("\n"); } /* * Check for format errors. Bug proofing. */ if (n < CTL_HEADER_LEN) { if (debug) printf("Short (%d byte) packet received\n", n); goto again; } if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) { if (debug) printf("Packet received with version %d\n", PKT_VERSION(rpkt.li_vn_mode)); goto again; } if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) { if (debug) printf("Packet received with mode %d\n", PKT_MODE(rpkt.li_vn_mode)); goto again; } if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) { if (debug) printf("Received request packet, wanted response\n"); goto again; } /* * Check opcode and sequence number for a match. * Could be old data getting to us. */ if (ntohs(rpkt.sequence) != sequence) { if (debug) printf( "Received sequnce number %d, wanted %d\n", ntohs(rpkt.sequence), sequence); goto again; } if (CTL_OP(rpkt.r_m_e_op) != opcode) { if (debug) printf( "Received opcode %d, wanted %d (sequence number okay)\n", CTL_OP(rpkt.r_m_e_op), opcode); goto again; } /* * Check the error code. If non-zero, return it. */ if (CTL_ISERROR(rpkt.r_m_e_op)) { int errcode; errcode = (ntohs(rpkt.status) >> 8) & 0xff; if (debug && CTL_ISMORE(rpkt.r_m_e_op)) { printf("Error code %d received on not-final packet\n", errcode); } if (errcode == CERR_UNSPEC) return ERR_UNSPEC; return errcode; } /* * Check the association ID to make sure it matches what * we sent. */ if (ntohs(rpkt.associd) != associd) { if (debug) printf("Association ID %d doesn't match expected %d\n", ntohs(rpkt.associd), associd); /* * Hack for silly fuzzballs which, at the time of writing, * return an assID of sys.peer when queried for system variables. */#ifdef notdef goto again;#endif } /* * Collect offset and count. Make sure they make sense. */ offset = ntohs(rpkt.offset); count = ntohs(rpkt.count); if (debug >= 3) { int shouldbesize; u_long key; u_long *lpkt; int maclen; /* * Usually we ignore authentication, but for debugging purposes * we watch it here. */ shouldbesize = CTL_HEADER_LEN + count; /* round to 8 octet boundary */ shouldbesize = (shouldbesize + 7) & ~7; if (n & 0x3) { printf("Packet not padded, size = %d\n", n); } if ((maclen = n - shouldbesize) >= MIN_MAC_LEN) { printf( "Packet shows signs of authentication (total %d, data %d, mac %d)\n", n, shouldbesize, maclen); lpkt = (u_long *)&rpkt; printf("%08lx %08lx %08lx %08lx %08lx %08lx\n", (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]), (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]), (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]), (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]), (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]), (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2])); key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]); printf("Authenticated with keyid %lu\n", (u_long)key); if (key != 0 && key != info_auth_keyid) { printf("We don't know that key\n"); } else { if (authdecrypt(key, (u_int32 *)&rpkt, n - maclen, maclen)) { printf("Auth okay!\n"); } else { printf("Auth failed!\n"); } } } } if (debug >= 2) printf("Got packet, size = %d\n", n); if (count > (u_short)(n-CTL_HEADER_LEN)) { if (debug) printf( "Received count of %d octets, data in packet is %d\n", count, n-CTL_HEADER_LEN); goto again; } if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) { if (debug) printf("Received count of 0 in non-final fragment\n"); goto again; } if (offset + count > sizeof(pktdata)) { if (debug) printf("Offset %d, count %d, too big for buffer\n", offset, count); return ERR_TOOMUCH; } if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) { if (debug) printf("Received second last fragment packet\n"); goto again; } /* * So far, so good. Record this fragment, making sure it doesn't * overlap anything. */ if (debug >= 2) printf("Packet okay\n");; if (numfrags == MAXFRAGS) { if (debug) printf("Number of fragments exceeds maximum\n"); return ERR_TOOMUCH; } for (n = 0; n < numfrags; n++) { if (offset == offsets[n]) goto again; /* duplicate */ if (offset < offsets[n]) break; } if ((u_short)(n > 0 && offsets[n-1] + counts[n-1]) > offset) goto overlap; if (n < numfrags && (u_short)(offset + count) > offsets[n]) goto overlap; { register int i; for (i = numfrags; i > n; i--) { offsets[i] = offsets[i-1]; counts[i] = counts[i-1]; } } offsets[n] = offset; counts[n] = count; numfrags++; /* * Got that stuffed in right. Figure out if this was the last. * Record status info out of the last packet. */ if (!CTL_ISMORE(rpkt.r_m_e_op)) { seenlastfrag = 1; if (rstatus != 0) *rstatus = ntohs(rpkt.status); } /* * Copy the data into the data buffer. */ memmove((char *)pktdata + offset, (char *)rpkt.data, count); /* * If we've seen the last fragment, look for holes in the sequence. * If there aren't any, we're done. */ if (seenlastfrag && offsets[0] == 0) { for (n = 1; n < numfrags; n++) { if (offsets[n-1] + counts[n-1] != offsets[n]) break; } if (n == numfrags) { *rsize = offsets[numfrags-1] + counts[numfrags-1]; return 0; } } goto again; overlap: /* * Print debugging message about overlapping fragments */ if (debug) printf("Overlapping fragments returned in response\n"); goto again;}/* * sendrequest - format and send a request packet */static intsendrequest( int opcode, int associd, int auth, int qsize, char *qdata ){ struct ntp_control qpkt; int pktsize; /* * Check to make sure the data will fit in one packet */ if (qsize > CTL_MAX_DATA_LEN) { (void) fprintf(stderr, "***Internal error! qsize (%d) too large\n", qsize); return 1; } /* * Fill in the packet */ qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL); qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK); qpkt.sequence = htons(sequence); qpkt.status = 0; qpkt.associd = htons((u_short)associd); qpkt.offset = 0; qpkt.count = htons((u_short)qsize); /* * If we have data, copy it in and pad it out to a 64 * bit boundary. */ if (qsize > 0) { memmove((char *)qpkt.data, qdata, (unsigned)qsize); pktsize = qsize + CTL_HEADER_LEN; while (pktsize & (sizeof(u_long) - 1)) { qpkt.data[qsize++] = 0; pktsize++; } } else { pktsize = CTL_HEADER_LEN; } /* * If it isn't authenticated we can just send it. Otherwise * we're going to have to think about it a little. */ if (!auth && !always_auth) { return sendpkt((char *)&qpkt, pktsize); } else { const char *pass = "\0"; int maclen = 0; u_long my_keyid; /* * Pad out packet to a multiple of 8 octets to be sure * receiver can handle it. */ while (pktsize & 7) { qpkt.data[qsize++] = 0; pktsize++; } /* * Get the keyid and the password if we don't have one. */ if (info_auth_keyid == 0) { int u_keyid = getkeyid("Keyid: "); if (u_keyid == 0 || u_keyid > NTP_MAXKEY) { (void) fprintf(stderr, "Invalid key identifier\n"); return 1; } info_auth_keyid = u_keyid; } if (!authistrusted(info_auth_keyid)) { pass = getpass("MD5 Password: "); if (*pass == '\0') { (void) fprintf(stderr, "Invalid password\n"); return (1); } } authusekey(info_auth_keyid, info_auth_keytype, (const u_char *)pass); authtrust(info_auth_keyid, 1); /* * Stick the keyid in the packet where * cp currently points. Cp should be aligned * properly. Then do the encryptions. */ my_keyid = htonl(info_auth_keyid); memcpy(&qpkt.data[qsize], &my_keyid, sizeof my_keyid); maclen = authencrypt(info_auth_keyid, (u_int32 *)&qpkt, pktsize); if (maclen == 0) { (void) fprintf(stderr, "Key not found\n"); return (1); } return sendpkt((char *)&qpkt, pktsize + maclen); } /*NOTREACHED*/}/* * doquery - send a request and process the response */intdoquery( int opcode, int associd, int auth, int qsize, char *qdata, u_short *rstatus, int *rsize, char **rdata ){ int res; int done; /* * Check to make sure host is open
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -