📄 ntp_proto.c
字号:
* than 5, an extension field is present, so we subtract the * length of the field and go around again. */ authlen = LEN_PKT_NOMAC; has_mac = rbufp->recv_length - authlen; while (has_mac > 0) { int temp; if (has_mac % 4 != 0 || has_mac < 0) { sys_badlength++; return; /* bad MAC length */ } if (has_mac == 1 * 4 || has_mac == 3 * 4 || has_mac == MAX_MAC_LEN) { skeyid = ntohl(((u_int32 *)pkt)[authlen / 4]); break; } else if (has_mac > MAX_MAC_LEN) { temp = ntohl(((u_int32 *)pkt)[authlen / 4]) & 0xffff; if (temp < 4 || temp > NTP_MAXEXTEN || temp % 4 != 0) { sys_badlength++; return; /* bad MAC length */ } authlen += temp; has_mac -= temp; } else { sys_badlength++; return; /* bad MAC length */ } }#ifdef OPENSSL pkeyid = tkeyid = 0;#endif /* OPENSSL */ /* * We have tossed out as many buggy packets as possible early in * the game to reduce the exposure to a clogging attack. Now we * have to burn some cycles to find the association and * authenticate the packet if required. Note that we burn only * MD5 cycles, again to reduce exposure. There may be no * matching association and that's okay. * * More on the autokey mambo. Normally the local interface is * found when the association was mobilized with respect to a * designated remote address. We assume packets arriving from * the remote address arrive via this interface and the local * address used to construct the autokey is the unicast address * of the interface. However, if the sender is a broadcaster, * the interface broadcast address is used instead. & Notwithstanding this technobabble, if the sender is a * multicaster, the broadcast address is null, so we use the * unicast address anyway. Don't ask. */ peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, hismode, &retcode); dstadr_sin = &rbufp->dstadr->sin; NTOHL_FP(&pkt->org, &p_org); NTOHL_FP(&pkt->rec, &p_rec); NTOHL_FP(&pkt->xmt, &p_xmt); /* * Authentication is conditioned by three switches: * * NOPEER (RES_NOPEER) do not mobilize an association unless * authenticated * NOTRUST (RES_DONTTRUST) do not allow access unless * authenticated (implies NOPEER) * enable (sys_authenticate) master NOPEER switch, by default * on * * The NOPEER and NOTRUST can be specified on a per-client basis * using the restrict command. The enable switch if on implies * NOPEER for all clients. There are four outcomes: * * NONE The packet has no MAC. * OK the packet has a MAC and authentication succeeds * ERROR the packet has a MAC and authentication fails * CRYPTO crypto-NAK. The MAC has four octets only. * * Note: The AUTH(x, y) macro is used to filter outcomes. If x * is zero, acceptable outcomes of y are NONE and OK. If x is * one, the only acceptable outcome of y is OK. */ if (has_mac == 0) { is_authentic = AUTH_NONE; /* not required */#ifdef DEBUG if (debug) printf("receive: at %ld %s<-%s mode %d code %d auth %d\n", current_time, stoa(dstadr_sin), stoa(&rbufp->recv_srcadr), hismode, retcode, is_authentic);#endif } else if (has_mac == 4) { is_authentic = AUTH_CRYPTO; /* crypto-NAK */#ifdef DEBUG if (debug) printf( "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", current_time, stoa(dstadr_sin), stoa(&rbufp->recv_srcadr), hismode, retcode, skeyid, authlen, has_mac, is_authentic);#endif } else {#ifdef OPENSSL /* * For autokey modes, generate the session key * and install in the key cache. Use the socket * broadcast or unicast address as appropriate. */ if (skeyid > NTP_MAXKEY) { /* * More on the autokey dance (AKD). A cookie is * constructed from public and private values. * For broadcast packets, the cookie is public * (zero). For packets that match no * association, the cookie is hashed from the * addresses and private value. For server * packets, the cookie was previously obtained * from the server. For symmetric modes, the * cookie was previously constructed using an * agreement protocol; however, should PKI be * unavailable, we construct a fake agreement as * the EXOR of the peer and host cookies. * * hismode ephemeral persistent * ======================================= * active 0 cookie# * passive 0% cookie# * client sys cookie 0% * server 0% sys cookie * broadcast 0 0 * * # if unsync, 0 * % can't happen */ if (hismode == MODE_BROADCAST) { /* * For broadcaster, use the interface * broadcast address when available; * otherwise, use the unicast address * found when the association was * mobilized. However, if this is from * the wildcard interface, game over. */ if (crypto_flags && rbufp->dstadr == any_interface) { sys_restricted++; return; /* no wildcard */ } pkeyid = 0; if (!SOCKNUL(&rbufp->dstadr->bcast)) dstadr_sin = &rbufp->dstadr->bcast; } else if (peer == NULL) { pkeyid = session_key( &rbufp->recv_srcadr, dstadr_sin, 0, sys_private, 0); } else { pkeyid = peer->pcookie; } /* * The session key includes both the public * values and cookie. In case of an extension * field, the cookie used for authentication * purposes is zero. Note the hash is saved for * use later in the autokey mambo. */ if (authlen > LEN_PKT_NOMAC && pkeyid != 0) { session_key(&rbufp->recv_srcadr, dstadr_sin, skeyid, 0, 2); tkeyid = session_key( &rbufp->recv_srcadr, dstadr_sin, skeyid, pkeyid, 0); } else { tkeyid = session_key( &rbufp->recv_srcadr, dstadr_sin, skeyid, pkeyid, 2); } }#endif /* OPENSSL */ /* * Compute the cryptosum. Note a clogging attack may * succeed in bloating the key cache. If an autokey, * purge it immediately, since we won't be needing it * again. If the packet is authentic, it can mobilize an * association. Note that there is no key zero. */ if (!authdecrypt(skeyid, (u_int32 *)pkt, authlen, has_mac)) { is_authentic = AUTH_ERROR; sys_badauth++; } else { is_authentic = AUTH_OK; }#ifdef OPENSSL if (skeyid > NTP_MAXKEY) authtrust(skeyid, 0);#endif /* OPENSSL */#ifdef DEBUG if (debug) printf( "receive: at %ld %s<-%s mode %d code %d keyid %08x len %d mac %d auth %d\n", current_time, stoa(dstadr_sin), stoa(&rbufp->recv_srcadr), hismode, retcode, skeyid, authlen, has_mac, is_authentic);#endif } /* * The association matching rules are implemented by a set of * routines and an association table. A packet matching an * association is processed by the peer process for that * association. If there are no errors, an ephemeral association * is mobilized: a broadcast packet mobilizes a broadcast client * aassociation; a manycast server packet mobilizes a manycast * client association; a symmetric active packet mobilizes a * symmetric passive association. */ switch (retcode) { /* * This is a client mode packet not matching any association. If * an ordinary client, simply toss a server mode packet back * over the fence. If a manycast client, we have to work a * little harder. */ case AM_FXMIT: /* * The vanilla case is when this is not a multicast * interface. If authentication succeeds, return a * server mode packet; if not and the key ID is nonzero, * return a crypto-NAK. */ if (!(rbufp->dstadr->flags & INT_MCASTOPEN)) { if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); else if (is_authentic == AUTH_ERROR) fast_xmit(rbufp, MODE_SERVER, 0, restrict_mask); return; /* hooray */ } /* * This must be manycast. Do not respond if not * configured as a manycast server. */ if (!sys_manycastserver) { sys_restricted++; return; /* not enabled */ } /* * Do not respond if unsynchronized or stratum is below * the floor or at or above the ceiling. */ if (sys_leap == LEAP_NOTINSYNC || sys_stratum < sys_floor || sys_stratum >= sys_ceiling) return; /* bad stratum */ /* * Do not respond if our stratum is greater than the * manycaster or it has already synchronized to us. */ if (sys_peer == NULL || hisstratum < sys_stratum || (sys_cohort && hisstratum == sys_stratum) || rbufp->dstadr->addr_refid == pkt->refid) return; /* no help */ /* * Respond only if authentication succeeds. Don't do a * crypto-NAK, as that would not be useful. */ if (AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) fast_xmit(rbufp, MODE_SERVER, skeyid, restrict_mask); return; /* hooray */ /* * This is a server mode packet returned in response to a client * mode packet sent to a multicast group address. The origin * timestamp is a good nonce to reliably associate the reply * with what was sent. If there is no match, that's curious and * could be an intruder attempting to clog, so we just ignore * it. * * If the packet is authentic and the manycast association is * found, we mobilize a client association and copy pertinent * variables from the manycast association to the new client * association. If not, just ignore the packet. * * There is an implosion hazard at the manycast client, since * the manycast servers send the server packet immediately. If * the guy is already here, don't fire up a duplicate. */ case AM_MANYCAST: if (!AUTH(sys_authenticate | (restrict_mask & (RES_NOPEER | RES_DONTTRUST)), is_authentic)) return; /* bad auth */ if ((peer2 = findmanycastpeer(rbufp)) == NULL) { sys_restricted++; return; /* not enabled */ } if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_CLIENT, hisversion, NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_IBURST | FLAG_PREEMPT, MDF_UCAST | MDF_ACLNT, 0, skeyid)) == NULL) return; /* system error */ /* * We don't need these, but it warms the billboards. */ peer->ttl = peer2->ttl; break; /* * This is the first packet received from a broadcast server. If * the packet is authentic and we are enabled as broadcast * client, mobilize a broadcast client association. We don't * kiss any frogs here. */ case AM_NEWBCL: if (!AUTH(sys_authenticate | (restrict_mask & (RES_NOPEER | RES_DONTTRUST)), is_authentic)) return; /* bad auth */ /* * Do not respond if unsynchronized or stratum is below * the floor or at or above the ceiling. */ if (hisleap == LEAP_NOTINSYNC || hisstratum < sys_floor || hisstratum >= sys_ceiling) return; /* bad stratum */ switch (sys_bclient) { /* * If not enabled, just skedaddle. */ case 0: sys_restricted++; return; /* not enabled */ /* * Execute the initial volley in order to calibrate the * propagation delay and run the Autokey protocol, if * enabled. */ case 1: if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_CLIENT, hisversion, NTP_MINDPOLL, NTP_MAXDPOLL, FLAG_MCAST | FLAG_IBURST, MDF_BCLNT, 0, skeyid)) == NULL) return; /* system error */#ifdef OPENSSL if (skeyid > NTP_MAXKEY) crypto_recv(peer, rbufp);#endif /* OPENSSL */ return; /* hooray */ /* * Do not execute the initial volley. */ case 2:#ifdef OPENSSL /* * If a two-way exchange is not possible, * neither is Autokey. */ if (skeyid > NTP_MAXKEY) { msyslog(LOG_INFO, "receive: autokey requires two-way communication"); return; /* no autokey */ }#endif /* OPENSSL */ if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_BCLIENT, hisversion, NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_BCLNT, 0, skeyid)) == NULL) return; /* system error */ } break; /* * This is the first packet received from a symmetric active * peer. If the packet is authentic and the first he sent, * mobilize a passive association. If not, kiss the frog. */ case AM_NEWPASS: /* * If the inbound packet is correctly authenticated and * enabled, a symmetric passive association is * mobilized. If not but correctly authenticated, a * symmetric active response is sent. If authentication * fails, send a crypto-NAK packet. */ if (!AUTH(restrict_mask & RES_DONTTRUST, is_authentic)) { if (is_authentic == AUTH_ERROR) fast_xmit(rbufp, MODE_ACTIVE, 0, restrict_mask); return; /* bad auth */ } if (!AUTH(sys_authenticate | (restrict_mask & RES_NOPEER), is_authentic)) { fast_xmit(rbufp, MODE_ACTIVE, skeyid, restrict_mask); return; /* hooray */ } /* * Do not respond if stratum is below the floor. */ if (hisstratum < sys_floor) return; /* bad stratum */ if ((peer = newpeer(&rbufp->recv_srcadr, rbufp->dstadr, MODE_PASSIVE, hisversion, NTP_MINDPOLL, NTP_MAXDPOLL, 0, MDF_UCAST, 0, skeyid)) == NULL) return; /* system error */ break; /* * Process regular packet. Nothing special. */ case AM_PROCPKT: break; /* * A passive packet matches a passive association. This is * usually the result of reconfiguring a client on the fly. As * this association might be legitamate and this packet an * attempt to deny service, just ignore it. */ case AM_ERR: return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -