📄 ntp_intres.c
字号:
openntp(void){ struct addrinfo hints; struct addrinfo *addrResult; const char *localhost = "127.0.0.1"; /* Use IPv6 loopback */ if (sockfd >= 0) return; memset(&hints, 0, sizeof(hints)); /* * For now only bother with IPv4 */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; if (getaddrinfo(localhost, "ntp", &hints, &addrResult)!=0) { msyslog(LOG_ERR, "getaddrinfo failed: %m"); resolver_exit(1); } sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0); if (sockfd == -1) { msyslog(LOG_ERR, "socket() failed: %m"); resolver_exit(1); } /* * Make the socket non-blocking. We'll wait with select() */#ifndef SYS_WINNT#if defined(O_NONBLOCK) if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) { msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m"); resolver_exit(1); }#else#if defined(FNDELAY) if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) { msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m"); resolver_exit(1); }#else# include "Bletch: NEED NON BLOCKING IO"#endif /* FNDDELAY */#endif /* O_NONBLOCK */#else /* SYS_WINNT */ { int on = 1; if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) { msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m"); resolver_exit(1); /* Windows NT - set socket in non-blocking mode */ } }#endif /* SYS_WINNT */ if (connect(sockfd, addrResult->ai_addr, addrResult->ai_addrlen) == -1) { msyslog(LOG_ERR, "openntp: connect() failed: %m"); resolver_exit(1); } freeaddrinfo(addrResult);}/* * request - send a configuration request to the server, wait for a response */static intrequest( struct conf_peer *conf ){ fd_set fdset; struct timeval tvout; struct req_pkt reqpkt; l_fp ts; int n;#ifdef SYS_WINNT HANDLE hReadWriteEvent = NULL; BOOL ret; DWORD NumberOfBytesWritten, NumberOfBytesRead, dwWait; OVERLAPPED overlap;#endif /* SYS_WINNT */ checkparent(); /* make sure our guy is still running */ if (sockfd == INVALID_SOCKET) openntp(); #ifdef SYS_WINNT hReadWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);#endif /* SYS_WINNT */ /* * Try to clear out any previously received traffic so it * doesn't fool us. Note the socket is nonblocking. */ tvout.tv_sec = 0; tvout.tv_usec = 0; FD_ZERO(&fdset); FD_SET(sockfd, &fdset); while (select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout) > 0) { recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); FD_ZERO(&fdset); FD_SET(sockfd, &fdset); } /* * Make up a request packet with the configuration info */ memset((char *)&reqpkt, 0, sizeof(reqpkt)); reqpkt.rm_vn_mode = RM_VN_MODE(0, 0, 0); reqpkt.auth_seq = AUTH_SEQ(1, 0); /* authenticated, no seq */ reqpkt.implementation = IMPL_XNTPD; /* local implementation */ reqpkt.request = REQ_CONFIG; /* configure a new peer */ reqpkt.err_nitems = ERR_NITEMS(0, 1); /* one item */ reqpkt.mbz_itemsize = MBZ_ITEMSIZE(sizeof(struct conf_peer)); /* Make sure mbz_itemsize <= sizeof reqpkt.data */ if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) { msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!"); resolver_exit(1); } memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer)); reqpkt.keyid = htonl(req_keyid); get_systime(&ts); L_ADDUF(&ts, SKEWTIME); HTONL_FP(&ts, &reqpkt.tstamp); n = 0; if (sys_authenticate) n = authencrypt(req_keyid, (u_int32 *)&reqpkt, REQ_LEN_NOMAC); /* * Done. Send it. */#ifndef SYS_WINNT n = send(sockfd, (char *)&reqpkt, (unsigned)(REQ_LEN_NOMAC + n), 0); if (n < 0) { msyslog(LOG_ERR, "send to NTP server failed: %m"); return 0; /* maybe should exit */ }#else /* In the NT world, documentation seems to indicate that there * exist _write and _read routines that can be used to do blocking * I/O on sockets. Problem is these routines require a socket * handle obtained through the _open_osf_handle C run-time API * of which there is no explanation in the documentation. We need * nonblocking write's and read's anyway for our purpose here. * We're therefore forced to deviate a little bit from the Unix * model here and use the ReadFile and WriteFile Win32 I/O API's * on the socket */ overlap.Offset = overlap.OffsetHigh = (DWORD)0; overlap.hEvent = hReadWriteEvent; ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n, NULL, (LPOVERLAPPED)&overlap); if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { msyslog(LOG_ERR, "send to NTP server failed: %m"); return 0; } dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { if (dwWait == WAIT_FAILED) msyslog(LOG_ERR, "WaitForSingleObject failed: %m"); return 0; } if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap, (LPDWORD)&NumberOfBytesWritten, FALSE)) { msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m"); return 0; }#endif /* SYS_WINNT */ /* * Wait for a response. A weakness of the mode 7 protocol used * is that there is no way to associate a response with a * particular request, i.e. the response to this configuration * request is indistinguishable from that to any other. I should * fix this some day. In any event, the time out is fairly * pessimistic to make sure that if an answer is coming back * at all, we get it. */ for (;;) { FD_ZERO(&fdset); FD_SET(sockfd, &fdset); tvout.tv_sec = TIMEOUT_SEC; tvout.tv_usec = TIMEOUT_USEC; n = select(sockfd + 1, &fdset, (fd_set *)0, (fd_set *)0, &tvout); if (n < 0) { if (errno != EINTR) msyslog(LOG_ERR, "select() fails: %m"); return 0; } else if (n == 0) { if (debug) msyslog(LOG_INFO, "select() returned 0."); return 0; }#ifndef SYS_WINNT n = recv(sockfd, (char *)&reqpkt, REQ_LEN_MAC, 0); if (n <= 0) { if (n < 0) { msyslog(LOG_ERR, "recv() fails: %m"); return 0; } continue; }#else /* Overlapped I/O used on non-blocking sockets on Windows NT */ ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC, NULL, (LPOVERLAPPED)&overlap); if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) { msyslog(LOG_ERR, "ReadFile() fails: %m"); return 0; } dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000); if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) { if (dwWait == WAIT_FAILED) { msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m"); return 0; } continue; } if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap, (LPDWORD)&NumberOfBytesRead, FALSE)) { msyslog(LOG_ERR, "GetOverlappedResult fails: %m"); return 0; } n = NumberOfBytesRead;#endif /* SYS_WINNT */ /* * Got one. Check through to make sure it is what * we expect. */ if (n < RESP_HEADER_SIZE) { msyslog(LOG_ERR, "received runt response (%d octets)", n); continue; } if (!ISRESPONSE(reqpkt.rm_vn_mode)) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "received non-response packet");#endif continue; } if (ISMORE(reqpkt.rm_vn_mode)) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "received fragmented packet");#endif continue; } if ( ( (INFO_VERSION(reqpkt.rm_vn_mode) < 2) || (INFO_VERSION(reqpkt.rm_vn_mode) > NTP_VERSION)) || INFO_MODE(reqpkt.rm_vn_mode) != MODE_PRIVATE) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "version (%d/%d) or mode (%d/%d) incorrect", INFO_VERSION(reqpkt.rm_vn_mode), NTP_VERSION, INFO_MODE(reqpkt.rm_vn_mode), MODE_PRIVATE);#endif continue; } if (INFO_SEQ(reqpkt.auth_seq) != 0) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "nonzero sequence number (%d)", INFO_SEQ(reqpkt.auth_seq));#endif continue; } if (reqpkt.implementation != IMPL_XNTPD || reqpkt.request != REQ_CONFIG) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "implementation (%d) or request (%d) incorrect", reqpkt.implementation, reqpkt.request);#endif continue; } if (INFO_NITEMS(reqpkt.err_nitems) != 0 || INFO_MBZ(reqpkt.mbz_itemsize) != 0 || INFO_ITEMSIZE(reqpkt.mbz_itemsize) != 0) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "nitems (%d) mbz (%d) or itemsize (%d) nonzero", INFO_NITEMS(reqpkt.err_nitems), INFO_MBZ(reqpkt.mbz_itemsize), INFO_ITEMSIZE(reqpkt.mbz_itemsize));#endif continue; } n = INFO_ERR(reqpkt.err_nitems); switch (n) { case INFO_OKAY: /* success */ return 1; case INFO_ERR_IMPL: msyslog(LOG_ERR, "ntpd reports implementation mismatch!"); return 0; case INFO_ERR_REQ: msyslog(LOG_ERR, "ntpd says configuration request is unknown!"); return 0; case INFO_ERR_FMT: msyslog(LOG_ERR, "ntpd indicates a format error occurred!"); return 0; case INFO_ERR_NODATA: msyslog(LOG_ERR, "ntpd indicates no data available!"); return 0; case INFO_ERR_AUTH: msyslog(LOG_ERR, "ntpd returns a permission denied error!"); return 0; default: msyslog(LOG_ERR, "ntpd returns unknown error code %d!", n); return 0; } }}/* * nexttoken - return the next token from a line */static char *nexttoken( char **lptr ){ register char *cp; register char *tstart; cp = *lptr; /* * Skip leading white space */ while (*cp == ' ' || *cp == '\t') cp++; /* * If this is the end of the line, return nothing. */ if (*cp == '\n' || *cp == '\0') { *lptr = cp; return NULL; } /* * Must be the start of a token. Record the pointer and look * for the end. */ tstart = cp++; while (*cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0') cp++; /* * Terminate the token with a \0. If this isn't the end of the * line, space to the next character. */ if (*cp == '\n' || *cp == '\0') *cp = '\0'; else *cp++ = '\0'; *lptr = cp; return tstart;}/* * readconf - read the configuration information out of the file we * were passed. Note that since the file is supposed to be * machine generated, we bail out at the first sign of trouble. */static voidreadconf( FILE *fp, char *name ){ register int i; char *token[NUMTOK]; u_long intval[NUMTOK]; u_int flags; char buf[MAXLINESIZE]; char *bp; while (fgets(buf, MAXLINESIZE, fp) != NULL) { bp = buf; for (i = 0; i < NUMTOK; i++) { if ((token[i] = nexttoken(&bp)) == NULL) { msyslog(LOG_ERR, "tokenizing error in file `%s', quitting", name); resolver_exit(1); } } for (i = 1; i < NUMTOK - 1; i++) { if (!atouint(token[i], &intval[i])) { msyslog(LOG_ERR, "format error for integer token `%s', file `%s', quitting", token[i], name); resolver_exit(1); } } if (intval[TOK_HMODE] != MODE_ACTIVE && intval[TOK_HMODE] != MODE_CLIENT && intval[TOK_HMODE] != MODE_BROADCAST) { msyslog(LOG_ERR, "invalid mode (%ld) in file %s", intval[TOK_HMODE], name); resolver_exit(1); } if (intval[TOK_VERSION] > NTP_VERSION || intval[TOK_VERSION] < NTP_OLDVERSION) { msyslog(LOG_ERR, "invalid version (%ld) in file %s", intval[TOK_VERSION], name); resolver_exit(1); } if (intval[TOK_MINPOLL] < NTP_MINPOLL || intval[TOK_MINPOLL] > NTP_MAXPOLL) { msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s", intval[TOK_MINPOLL], name); resolver_exit(1); } if (intval[TOK_MAXPOLL] < NTP_MINPOLL || intval[TOK_MAXPOLL] > NTP_MAXPOLL) { msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s", intval[TOK_MAXPOLL], name); resolver_exit(1); } if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER | FLAG_NOSELECT | FLAG_BURST | FLAG_IBURST | FLAG_SKEY)) != 0) { msyslog(LOG_ERR, "invalid flags (%ld) in file %s", intval[TOK_FLAGS], name); resolver_exit(1); } flags = 0; if (intval[TOK_FLAGS] & FLAG_AUTHENABLE) flags |= CONF_FLAG_AUTHENABLE; if (intval[TOK_FLAGS] & FLAG_PREFER) flags |= CONF_FLAG_PREFER; if (intval[TOK_FLAGS] & FLAG_NOSELECT) flags |= CONF_FLAG_NOSELECT; if (intval[TOK_FLAGS] & FLAG_BURST) flags |= CONF_FLAG_BURST; if (intval[TOK_FLAGS] & FLAG_IBURST) flags |= CONF_FLAG_IBURST; if (intval[TOK_FLAGS] & FLAG_SKEY) flags |= CONF_FLAG_SKEY; /* * This is as good as we can check it. Add it in. */ addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], intval[TOK_KEYID], token[TOK_KEYSTR]); }}/* * doconfigure - attempt to resolve names and configure the server */static voiddoconfigure( int dores ){ register struct conf_entry *ce; register struct conf_entry *ceremove; ce = confentries; while (ce != NULL) {#ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, "doconfigure: <%s> has peeraddr %s", ce->ce_name, stoa(&ce->peer_store));#endif if (dores && SOCKNUL(&(ce->peer_store))) { if (!findhostaddr(ce)) { msyslog(LOG_ERR, "couldn't resolve `%s', giving up on it", ce->ce_name); ceremove = ce; ce = ceremove->ce_next; removeentry(ceremove); continue; } } if (!SOCKNUL(&ce->peer_store)) { if (request(&ce->ce_config)) { ceremove = ce; ce = ceremove->ce_next; removeentry(ceremove); continue; }#ifdef DEBUG if (debug > 1) { msyslog(LOG_INFO, "doconfigure: request() FAILED, maybe next time."); }#endif } ce = ce->ce_next; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -