📄 ntp_proto.c
字号:
/* * For everything else there is the bit bucket. */ default: return; } peer->flash &= ~PKT_TEST_MASK; /* * Next comes a rigorous schedule of timestamp checking. If the * transmit timestamp is zero, the server is horribly broken. */ if (L_ISZERO(&p_xmt)) { return; /* read rfc1305 */ /* * If the transmit timestamp duplicates a previous one, the * packet is a replay. This prevents the bad guys from replaying * the most recent packet, authenticated or not. */ } else if (L_ISEQU(&peer->org, &p_xmt)) { peer->flash |= TEST1; peer->oldpkt++; return; /* duplicate packet */ /* * If this is a broadcast mode packet, skip further checking. */ } else if (hismode != MODE_BROADCAST) { if (L_ISZERO(&p_org)) peer->flash |= TEST3; /* protocol unsynch */ else if (!L_ISEQU(&p_org, &peer->xmt)) peer->flash |= TEST2; /* bogus packet */ } /* * Update the origin and destination timestamps. If * unsynchronized or bogus abandon ship. If the crypto machine * breaks, light the crypto bit and plaint the log. */ peer->org = p_xmt; peer->rec = rbufp->recv_time; if (peer->flash & PKT_TEST_MASK) {#ifdef OPENSSL if (crypto_flags && (peer->flags & FLAG_SKEY)) { rval = crypto_recv(peer, rbufp); if (rval != XEVNT_OK) { peer_clear(peer, "CRYP"); peer->flash |= TEST9; /* crypto error */ } }#endif /* OPENSSL */ return; /* unsynch */ } /* * The timestamps are valid and the receive packet matches the * last one sent. If the packet is a crypto-NAK, the server * might have just changed keys. We reset the association * and restart the protocol. */ if (is_authentic == AUTH_CRYPTO) { peer_clear(peer, "AUTH"); return; /* crypto-NAK */ /* * If the association is authenticated, the key ID is nonzero * and received packets must be authenticated. This is designed * to avoid a bait-and-switch attack, which was possible in past * versions. If symmetric modes, return a crypto-NAK. The peer * should restart the protocol. */ } else if (!AUTH(peer->keyid || (restrict_mask & RES_DONTTRUST), is_authentic)) { peer->flash |= TEST5; if (hismode == MODE_ACTIVE || hismode == MODE_PASSIVE) fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); return; /* bad auth */ } /* * That was hard and I am sweaty, but the packet is squeaky * clean. Get on with real work. */ peer->received++; peer->timereceived = current_time; if (is_authentic == AUTH_OK) peer->flags |= FLAG_AUTHENTIC; else peer->flags &= ~FLAG_AUTHENTIC;#ifdef OPENSSL /* * More autokey dance. The rules of the cha-cha are as follows: * * 1. If there is no key or the key is not auto, do nothing. * * 2. If this packet is in response to the one just previously * sent or from a broadcast server, do the extension fields. * Otherwise, assume bogosity and bail out. * * 3. If an extension field contains a verified signature, it is * self-authenticated and we sit the dance. * * 4. If this is a server reply, check only to see that the * transmitted key ID matches the received key ID. * * 5. Check to see that one or more hashes of the current key ID * matches the previous key ID or ultimate original key ID * obtained from the broadcaster or symmetric peer. If no * match, sit the dance and wait for timeout. * * In case of crypto error, fire the orchestra and stop dancing. * This is considered a permanant error, so light the crypto bit * to suppress further requests. If preemptable or ephemeral, * scuttle the ship. */ if (crypto_flags && (peer->flags & FLAG_SKEY)) { peer->flash |= TEST8; rval = crypto_recv(peer, rbufp); if (rval != XEVNT_OK) { peer_clear(peer, "CRYP"); peer->flash |= TEST9; /* crypto error */ if (peer->flags & FLAG_PREEMPT || !(peer->flags & FLAG_CONFIG)) unpeer(peer); return; } else if (hismode == MODE_SERVER) { if (skeyid == peer->keyid) peer->flash &= ~TEST8; } else if (!(peer->flash & TEST8)) { peer->pkeyid = skeyid; } else if ((ap = (struct autokey *)peer->recval.ptr) != NULL) { int i; for (i = 0; ; i++) { if (tkeyid == peer->pkeyid || tkeyid == ap->key) { peer->flash &= ~TEST8; peer->pkeyid = skeyid; break; } if (i > ap->seq) break; tkeyid = session_key( &rbufp->recv_srcadr, dstadr_sin, tkeyid, pkeyid, 0); } } if (!(peer->crypto & CRYPTO_FLAG_PROV)) /* test 9 */ peer->flash |= TEST8; /* not proventic */ /* * If the transmit queue is nonempty, clamp the host * poll interval to the packet poll interval. */ if (peer->cmmd != 0) { peer->ppoll = pkt->ppoll; poll_update(peer, peer->hpoll); } }#endif /* OPENSSL */ /* * The dance is complete and the flash bits have been lit. Toss * the packet over the fence for processing, which may light up * more flashers. */ process_packet(peer, pkt); /* * Well, that was nice. If TEST4 is lit, either the crypto * machine jammed or a kiss-o'-death packet flew in, either of * which is fatal. */ if (peer->flash & TEST4) { msyslog(LOG_INFO, "receive: fatal error %04x for %s", peer->flash, stoa(&peer->srcadr)); return; }}/* * process_packet - Packet Procedure, a la Section 3.4.4 of the * specification. Or almost, at least. If we're in here we have a * reasonable expectation that we will be having a long term * relationship with this host. */voidprocess_packet( register struct peer *peer, register struct pkt *pkt ){ double t34, t21; double p_offset, p_del, p_disp; l_fp p_rec, p_xmt, p_org, p_reftime; l_fp ci; u_char pmode, pleap, pstratum; sys_processed++; peer->processed++; p_del = FPTOD(NTOHS_FP(pkt->rootdelay)); p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion)); NTOHL_FP(&pkt->reftime, &p_reftime); NTOHL_FP(&pkt->rec, &p_rec); NTOHL_FP(&pkt->xmt, &p_xmt); pmode = PKT_MODE(pkt->li_vn_mode); pleap = PKT_LEAP(pkt->li_vn_mode); if (pmode != MODE_BROADCAST) NTOHL_FP(&pkt->org, &p_org); else p_org = peer->rec; pstratum = PKT_TO_STRATUM(pkt->stratum); /* * Test for kiss-o'death packet) */ if (pleap == LEAP_NOTINSYNC && pstratum == STRATUM_UNSPEC) { if (memcmp(&pkt->refid, "DENY", 4) == 0) { peer_clear(peer, "DENY"); peer->flash |= TEST4; /* access denied */ } } /* * Capture the header values. */ record_raw_stats(&peer->srcadr, &peer->dstadr->sin, &p_org, &p_rec, &p_xmt, &peer->rec); peer->leap = pleap; peer->stratum = min(pstratum, STRATUM_UNSPEC); peer->pmode = pmode; peer->ppoll = pkt->ppoll; peer->precision = pkt->precision; peer->rootdelay = p_del; peer->rootdispersion = p_disp; peer->refid = pkt->refid; /* network byte order */ peer->reftime = p_reftime; /* * Verify the server is synchronized; that is, the leap bits and * stratum are valid, the root delay and root dispersion are * valid and the reference timestamp is not later than the * transmit timestamp. */ if (pleap == LEAP_NOTINSYNC || /* test 6 */ pstratum < sys_floor || pstratum >= sys_ceiling) peer->flash |= TEST6; /* peer not synch */ if (p_del < 0 || p_disp < 0 || p_del / /* test 7 */ 2 + p_disp >= MAXDISPERSE || !L_ISHIS(&p_xmt, &p_reftime)) peer->flash |= TEST7; /* bad header */ /* * If any tests fail at this point, the packet is discarded. * Note that some flashers may have already been set in the * receive() routine. */ if (peer->flash & PKT_TEST_MASK) {#ifdef DEBUG if (debug) printf("packet: flash header %04x\n", peer->flash);#endif return; } if (!(peer->reach)) { report_event(EVNT_REACH, peer); peer->timereachable = current_time; } poll_update(peer, peer->hpoll); peer->reach |= 1; /* * For a client/server association, calculate the clock offset, * roundtrip delay and dispersion. The equations are reordered * from the spec for more efficient use of temporaries. For a * broadcast association, offset the last measurement by the * computed delay during the client/server volley. Note that * org has been set to the time of last reception. Note the * computation of dispersion includes the system precision plus * that due to the frequency error since the origin time. * * It is very important to respect the hazards of overflow. The * only permitted operation on raw timestamps is subtraction, * where the result is a signed quantity spanning from 68 years * in the past to 68 years in the future. To avoid loss of * precision, these calculations are done using 64-bit integer * arithmetic. However, the offset and delay calculations are * sums and differences of these first-order differences, which * if done using 64-bit integer arithmetic, would be valid over * only half that span. Since the typical first-order * differences are usually very small, they are converted to 64- * bit doubles and all remaining calculations done in floating- * point arithmetic. This preserves the accuracy while retaining * the 68-year span. * * Let t1 = p_org, t2 = p_rec, t3 = p_xmt, t4 = peer->rec: */ ci = p_xmt; /* t3 - t4 */ L_SUB(&ci, &peer->rec); LFPTOD(&ci, t34); ci = p_rec; /* t2 - t1 */ L_SUB(&ci, &p_org); LFPTOD(&ci, t21); ci = peer->rec; /* t4 - t1 */ L_SUB(&ci, &p_org); /* * If running in a broadcast association, the clock offset is * (t1 - t0) corrected by the one-way delay, but we can't * measure that directly. Therefore, we start up in MODE_CLIENT * mode, set FLAG_MCAST and exchange eight messages to determine * the clock offset. When the last message is sent, we switch to * MODE_BCLIENT mode. The next broadcast message after that * computes the broadcast offset and clears FLAG_MCAST. */ if (pmode == MODE_BROADCAST) { p_offset = t34; if (peer->flags & FLAG_MCAST) { peer->estbdelay = peer->offset - p_offset; if (peer->hmode == MODE_CLIENT) return; peer->flags &= ~(FLAG_MCAST | FLAG_BURST); } p_offset += peer->estbdelay; p_del = peer->delay; p_disp = 0; } else { p_offset = (t21 + t34) / 2.; p_del = t21 - t34; LFPTOD(&ci, p_disp); p_disp = LOGTOD(sys_precision) + LOGTOD(peer->precision) + clock_phi * p_disp; } p_del = max(p_del, LOGTOD(sys_precision)); clock_filter(peer, p_offset, p_del, p_disp); record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), peer->offset, peer->delay, peer->disp, peer->jitter);}/* * clock_update - Called at system process update intervals. */static voidclock_update(void){ u_char oleap; u_char ostratum; double dtemp; /* * There must be a system peer at this point. If we just changed * the system peer, but have a newer sample from the old one, * wait until newer data are available. */ if (sys_poll < sys_peer->minpoll) sys_poll = sys_peer->minpoll; if (sys_poll > sys_peer->maxpoll) sys_poll = sys_peer->maxpoll; poll_update(sys_peer, sys_poll); if (sys_peer->epoch <= sys_clocktime) return;#ifdef DEBUG if (debug) printf("clock_update: at %ld assoc %d \n", current_time, peer_associations);#endif oleap = sys_leap; ostratum = sys_stratum; switch (local_clock(sys_peer, sys_offset)) { /* * Clock exceeds panic threshold. Life as we know it ends. */ case -1: report_event(EVNT_SYSFAULT, NULL); exit (-1); /* not reached */ /* * Clock was stepped. Flush all time values of all peers. */ case 2: clear_all(); sys_leap = LEAP_NOTINSYNC; sys_stratum = STRATUM_UNSPEC; sys_peer = NULL; sys_rootdelay = 0; sys_rootdispersion = 0; memcpy(&sys_refid, "STEP", 4); sys_poll = NTP_MINPOLL; report_event(EVNT_CLOCKRESET, NULL); break; /* * Clock was slewed. Update the system stratum, leap bits, root * delay, root dispersion, reference ID and reference time. If * the leap changes, we gotta reroll the keys. Except for * reference clocks, the minimum dispersion increment is not * less than sys_mindisp. */ case 1: sys_leap = leap_next; sys_stratum = min(sys_peer->stratum + 1, STRATUM_UNSPEC); sys_reftime = sys_peer->rec; /* * In orphan mode the stratum defaults to the orphan * stratum. The root delay is set to a random value * generated at startup. The root dispersion is set from * the peer dispersion; the peer root dispersion is * ignored. */ dtemp = sys_peer->disp + clock_phi * (current_time - sys_peer->update) + sys_jitter + fabs(sys_peer->offset);#ifdef REFCLOCK if (!(sys_peer->flags & FLAG_REFCLOCK) && dtemp < sys_mindisp) dtemp = sys_mindisp;#else if (dtemp < sys_mindisp) dtemp = sys_mindisp;#endif /* REFCLOCK */ if (sys_stratum >= sys_orphan) { sys_stratum = sys_orphan; sys_rootdelay = sys_peer->delay; sys_rootdispersion = dtemp; } else { sys_rootdelay = sys_peer->delay + sys_peer->rootdelay; sys_rootdispersion = dtemp + sys_peer->rootdispersion; } if (oleap == LEAP_NOTINSYNC) { report_event(EVNT_SYNCCHG, NULL);#ifdef OPENSSL expire_all(); crypto_update();#endif /* OPENSSL */ } break; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -