Example #1
0
void
test_GenerateAuthenticatedPacket(void)
{
	static const int EXPECTED_PKTLEN = LEN_PKT_NOMAC + MAX_MD5_LEN;
	
	struct key	testkey;
	struct pkt	testpkt;
	struct timeval	xmt;
	l_fp		expected_xmt, actual_xmt;
	char 		expected_mac[MAX_MD5_LEN];
	
	testkey.next = NULL;
	testkey.key_id = 30;
	testkey.key_len = 9;
	memcpy(testkey.key_seq, "123456789", testkey.key_len);
	strlcpy(testkey.typen, "MD5", sizeof(testkey.typen));
	testkey.typei = keytype_from_text(testkey.typen, NULL);

	GETTIMEOFDAY(&xmt, NULL);
	xmt.tv_sec += JAN_1970;

	TEST_ASSERT_EQUAL(EXPECTED_PKTLEN,
			  generate_pkt(&testpkt, &xmt, testkey.key_id, &testkey));

	TEST_ASSERT_EQUAL(LEAP_NOTINSYNC, PKT_LEAP(testpkt.li_vn_mode));
	TEST_ASSERT_EQUAL(NTP_VERSION, PKT_VERSION(testpkt.li_vn_mode));
	TEST_ASSERT_EQUAL(MODE_CLIENT, PKT_MODE(testpkt.li_vn_mode));

	TEST_ASSERT_EQUAL(STRATUM_UNSPEC, PKT_TO_STRATUM(testpkt.stratum));
	TEST_ASSERT_EQUAL(8, testpkt.ppoll);

	TVTOTS(&xmt, &expected_xmt);
	NTOHL_FP(&testpkt.xmt, &actual_xmt);
	TEST_ASSERT_TRUE(LfpEquality(expected_xmt, actual_xmt));

	TEST_ASSERT_EQUAL(testkey.key_id, ntohl(testpkt.exten[0]));
	
	TEST_ASSERT_EQUAL(MAX_MD5_LEN - 4, /* Remove the key_id, only keep the mac. */
			  make_mac(&testpkt, LEN_PKT_NOMAC, MAX_MD5_LEN-4, &testkey, expected_mac));
	TEST_ASSERT_EQUAL_MEMORY(expected_mac, (char*)&testpkt.exten[1], MAX_MD5_LEN -4);
}
Example #2
0
TEST_F(mainTest, GenerateUnauthenticatedPacket) {
	pkt testpkt;

	timeval xmt;
	GETTIMEOFDAY(&xmt, NULL);
	xmt.tv_sec += JAN_1970;

	EXPECT_EQ(LEN_PKT_NOMAC,
			  generate_pkt(&testpkt, &xmt, 0, NULL));

	EXPECT_EQ(LEAP_NOTINSYNC, PKT_LEAP(testpkt.li_vn_mode));
	EXPECT_EQ(NTP_VERSION, PKT_VERSION(testpkt.li_vn_mode));
	EXPECT_EQ(MODE_CLIENT, PKT_MODE(testpkt.li_vn_mode));

	EXPECT_EQ(STRATUM_UNSPEC, PKT_TO_STRATUM(testpkt.stratum));
	EXPECT_EQ(8, testpkt.ppoll);

	l_fp expected_xmt, actual_xmt;
	TVTOTS(&xmt, &expected_xmt);
	NTOHL_FP(&testpkt.xmt, &actual_xmt);
	EXPECT_TRUE(LfpEquality(expected_xmt, actual_xmt));
}
Example #3
0
TEST_F(mainTest, GenerateAuthenticatedPacket) {
	key testkey;
	testkey.next = NULL;
	testkey.key_id = 30;
	testkey.key_len = 9;
	memcpy(testkey.key_seq, "123456789", testkey.key_len);
	memcpy(testkey.type, "MD5", 3);

	pkt testpkt;

	timeval xmt;
	GETTIMEOFDAY(&xmt, NULL);
	xmt.tv_sec += JAN_1970;

	const int EXPECTED_PKTLEN = LEN_PKT_NOMAC + MAX_MD5_LEN;

	EXPECT_EQ(EXPECTED_PKTLEN,
			  generate_pkt(&testpkt, &xmt, testkey.key_id, &testkey));

	EXPECT_EQ(LEAP_NOTINSYNC, PKT_LEAP(testpkt.li_vn_mode));
	EXPECT_EQ(NTP_VERSION, PKT_VERSION(testpkt.li_vn_mode));
	EXPECT_EQ(MODE_CLIENT, PKT_MODE(testpkt.li_vn_mode));

	EXPECT_EQ(STRATUM_UNSPEC, PKT_TO_STRATUM(testpkt.stratum));
	EXPECT_EQ(8, testpkt.ppoll);

	l_fp expected_xmt, actual_xmt;
	TVTOTS(&xmt, &expected_xmt);
	NTOHL_FP(&testpkt.xmt, &actual_xmt);
	EXPECT_TRUE(LfpEquality(expected_xmt, actual_xmt));

	EXPECT_EQ(testkey.key_id, ntohl(testpkt.exten[0]));
	
	char expected_mac[MAX_MD5_LEN];
	ASSERT_EQ(MAX_MD5_LEN - 4, // Remove the key_id, only keep the mac.
			  make_mac((char*)&testpkt, LEN_PKT_NOMAC, MAX_MD5_LEN, &testkey, expected_mac));
	EXPECT_TRUE(memcmp(expected_mac, (char*)&testpkt.exten[1], MAX_MD5_LEN -4) == 0);
}
Example #4
0
void
test_GenerateUnauthenticatedPacket(void)
{
	struct pkt	testpkt;
	struct timeval	xmt;
	l_fp		expected_xmt, actual_xmt;

	GETTIMEOFDAY(&xmt, NULL);
	xmt.tv_sec += JAN_1970;

	TEST_ASSERT_EQUAL(LEN_PKT_NOMAC,
			  generate_pkt(&testpkt, &xmt, 0, NULL));

	TEST_ASSERT_EQUAL(LEAP_NOTINSYNC, PKT_LEAP(testpkt.li_vn_mode));
	TEST_ASSERT_EQUAL(NTP_VERSION, PKT_VERSION(testpkt.li_vn_mode));
	TEST_ASSERT_EQUAL(MODE_CLIENT, PKT_MODE(testpkt.li_vn_mode));

	TEST_ASSERT_EQUAL(STRATUM_UNSPEC, PKT_TO_STRATUM(testpkt.stratum));
	TEST_ASSERT_EQUAL(8, testpkt.ppoll);

	TVTOTS(&xmt, &expected_xmt);
	NTOHL_FP(&testpkt.xmt, &actual_xmt);
	TEST_ASSERT_TRUE(LfpEquality(expected_xmt, actual_xmt));
}
Example #5
0
/*
 * ntp_monitor - record stats about this packet
 *
 * Returns supplied restriction flags, with RES_LIMITED and RES_KOD
 * cleared unless the packet should not be responded to normally
 * (RES_LIMITED) and possibly should trigger a KoD response (RES_KOD).
 * The returned flags are saved in the MRU entry, so that it reflects
 * whether the last packet from that source triggered rate limiting,
 * and if so, possible KoD response.  This implies you can not tell
 * whether a given address is eligible for rate limiting/KoD from the
 * monlist restrict bits, only whether or not the last packet triggered
 * such responses.  ntpdc -c reslist lets you see whether RES_LIMITED
 * or RES_KOD is lit for a particular address before ntp_monitor()'s
 * typical dousing.
 */
u_short
ntp_monitor(
    struct recvbuf *rbufp,
    u_short	flags
)
{
    l_fp		interval_fp;
    struct pkt *	pkt;
    mon_entry *	mon;
    mon_entry *	oldest;
    int		oldest_age;
    u_int		hash;
    u_short		restrict_mask;
    u_char		mode;
    u_char		version;
    int		interval;
    int		head;		/* headway increment */
    int		leak;		/* new headway */
    int		limit;		/* average threshold */

    REQUIRE(rbufp != NULL);

    if (mon_enabled == MON_OFF)
        return ~(RES_LIMITED | RES_KOD) & flags;

    pkt = &rbufp->recv_pkt;
    hash = MON_HASH(&rbufp->recv_srcadr);
    mode = PKT_MODE(pkt->li_vn_mode);
    version = PKT_VERSION(pkt->li_vn_mode);
    mon = mon_hash[hash];

    /*
     * We keep track of all traffic for a given IP in one entry,
     * otherwise cron'ed ntpdate or similar evades RES_LIMITED.
     */

    for (; mon != NULL; mon = mon->hash_next)
        if (SOCK_EQ(&mon->rmtadr, &rbufp->recv_srcadr))
            break;

    if (mon != NULL) {
        interval_fp = rbufp->recv_time;
        L_SUB(&interval_fp, &mon->last);
        /* add one-half second to round up */
        L_ADDUF(&interval_fp, 0x80000000);
        interval = interval_fp.l_i;
        mon->last = rbufp->recv_time;
        NSRCPORT(&mon->rmtadr) = NSRCPORT(&rbufp->recv_srcadr);
        mon->count++;
        restrict_mask = flags;
        mon->vn_mode = VN_MODE(version, mode);

        /* Shuffle to the head of the MRU list. */
        UNLINK_DLIST(mon, mru);
        LINK_DLIST(mon_mru_list, mon, mru);

        /*
         * At this point the most recent arrival is first in the
         * MRU list.  Decrease the counter by the headway, but
         * not less than zero.
         */
        mon->leak -= interval;
        mon->leak = max(0, mon->leak);
        head = 1 << ntp_minpoll;
        leak = mon->leak + head;
        limit = NTP_SHIFT * head;

        DPRINTF(2, ("MRU: interval %d headway %d limit %d\n",
                    interval, leak, limit));

        /*
         * If the minimum and average thresholds are not
         * exceeded, douse the RES_LIMITED and RES_KOD bits and
         * increase the counter by the headway increment.  Note
         * that we give a 1-s grace for the minimum threshold
         * and a 2-s grace for the headway increment.  If one or
         * both thresholds are exceeded and the old counter is
         * less than the average threshold, set the counter to
         * the average threshold plus the increment and leave
         * the RES_LIMITED and RES_KOD bits lit. Otherwise,
         * leave the counter alone and douse the RES_KOD bit.
         * This rate-limits the KoDs to no less than the average
         * headway.
         */
        if (interval + 1 >= ntp_minpkt && leak < limit) {
            mon->leak = leak - 2;
            restrict_mask &= ~(RES_LIMITED | RES_KOD);
        } else if (mon->leak < limit)
            mon->leak = limit + head;
        else
            restrict_mask &= ~RES_KOD;

        mon->flags = restrict_mask;

        return mon->flags;
    }

    /*
     * If we got here, this is the first we've heard of this
     * guy.  Get him some memory, either from the free list
     * or from the tail of the MRU list.
     *
     * The following ntp.conf "mru" knobs come into play determining
     * the depth (or count) of the MRU list:
     * - mru_mindepth ("mru mindepth") is a floor beneath which
     *   entries are kept without regard to their age.  The
     *   default is 600 which matches the longtime implementation
     *   limit on the total number of entries.
     * - mru_maxage ("mru maxage") is a ceiling on the age in
     *   seconds of entries.  Entries older than this are
     *   reclaimed once mon_mindepth is exceeded.  64s default.
     *   Note that entries older than this can easily survive
     *   as they are reclaimed only as needed.
     * - mru_maxdepth ("mru maxdepth") is a hard limit on the
     *   number of entries.
     * - "mru maxmem" sets mru_maxdepth to the number of entries
     *   which fit in the given number of kilobytes.  The default is
     *   1024, or 1 megabyte.
     * - mru_initalloc ("mru initalloc" sets the count of the
     *   initial allocation of MRU entries.
     * - "mru initmem" sets mru_initalloc in units of kilobytes.
     *   The default is 4.
     * - mru_incalloc ("mru incalloc" sets the number of entries to
     *   allocate on-demand each time the free list is empty.
     * - "mru incmem" sets mru_incalloc in units of kilobytes.
     *   The default is 4.
     * Whichever of "mru maxmem" or "mru maxdepth" occurs last in
     * ntp.conf controls.  Similarly for "mru initalloc" and "mru
     * initmem", and for "mru incalloc" and "mru incmem".
     */
    if (mru_entries < mru_mindepth) {
        if (NULL == mon_free)
            mon_getmoremem();
        UNLINK_HEAD_SLIST(mon, mon_free, hash_next);
    } else {
        oldest = TAIL_DLIST(mon_mru_list, mru);
        oldest_age = 0;		/* silence uninit warning */
        if (oldest != NULL) {
            interval_fp = rbufp->recv_time;
            L_SUB(&interval_fp, &oldest->last);
            /* add one-half second to round up */
            L_ADDUF(&interval_fp, 0x80000000);
            oldest_age = interval_fp.l_i;
        }
        /* note -1 is legal for mru_maxage (disables) */
        if (oldest != NULL && mru_maxage < oldest_age) {
            mon_reclaim_entry(oldest);
            mon = oldest;
        } else if (mon_free != NULL || mru_alloc <
                   mru_maxdepth) {
            if (NULL == mon_free)
                mon_getmoremem();
            UNLINK_HEAD_SLIST(mon, mon_free, hash_next);
            /* Preempt from the MRU list if old enough. */
        } else if (ntp_random() / (2. * FRAC) >
                   (double)oldest_age / mon_age) {
            return ~(RES_LIMITED | RES_KOD) & flags;
        } else {
            mon_reclaim_entry(oldest);
            mon = oldest;
        }
    }

    INSIST(mon != NULL);

    /*
     * Got one, initialize it
     */
    mru_entries++;
    mru_peakentries = max(mru_peakentries, mru_entries);
    mon->last = rbufp->recv_time;
    mon->first = mon->last;
    mon->count = 1;
    mon->flags = ~(RES_LIMITED | RES_KOD) & flags;
    mon->leak = 0;
    memcpy(&mon->rmtadr, &rbufp->recv_srcadr, sizeof(mon->rmtadr));
    mon->vn_mode = VN_MODE(version, mode);
    mon->lcladr = rbufp->dstadr;
    mon->cast_flags = (u_char)(((rbufp->dstadr->flags &
                                 INT_MCASTOPEN) && rbufp->fd == mon->lcladr->fd) ? MDF_MCAST
                               : rbufp->fd == mon->lcladr->bfd ? MDF_BCAST : MDF_UCAST);

    /*
     * Drop him into front of the hash table. Also put him on top of
     * the MRU list.
     */
    LINK_SLIST(mon_hash[hash], mon, hash_next);
    LINK_DLIST(mon_mru_list, mon, mru);

    return mon->flags;
}
Example #6
0
int
process_pkt (
	struct pkt *rpkt,
	sockaddr_u *sas,
	int pkt_len,
	int mode,
	struct pkt *spkt,
	const char * func_name
	)
{
	unsigned int key_id = 0;
	struct key *pkt_key = NULL;
	int is_authentic = 0;
	unsigned int exten_words, exten_words_used = 0;
	int mac_size;
	/*
	 * Parse the extension field if present. We figure out whether
	 * an extension field is present by measuring the MAC size. If
	 * the number of words following the packet header is 0, no MAC
	 * is present and the packet is not authenticated. If 1, the
	 * packet is a crypto-NAK; if 3, the packet is authenticated
	 * with DES; if 5, the packet is authenticated with MD5; if 6,
	 * the packet is authenticated with SHA. If 2 or 4, the packet
	 * is a runt and discarded forthwith. If greater than 6, an
	 * extension field is present, so we subtract the length of the
	 * field and go around again.
	 */
	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
unusable:
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Funny packet length: %i. Discarding package.\n", func_name, pkt_len);
		return PACKET_UNUSEABLE;
	}
	/* skip past the extensions, if any */
	exten_words = ((unsigned)pkt_len - LEN_PKT_NOMAC) >> 2;
	while (exten_words > 6) {
		unsigned int exten_len;
		exten_len = ntohl(rpkt->exten[exten_words_used]) & 0xffff;
		exten_len = (exten_len + 7) >> 2; /* convert to words, add 1 */
		if (exten_len > exten_words || exten_len < 5)
			goto unusable;
		exten_words -= exten_len;
		exten_words_used += exten_len;
	}

	switch (exten_words) {
	case 1:
		key_id = ntohl(rpkt->exten[exten_words_used]);
		printf("Crypto NAK = 0x%08x\n", key_id);
		break;
	case 5:
	case 6:
		/* Look for the key used by the server in the specified keyfile
		 * and if existent, fetch it or else leave the pointer untouched */
		key_id = ntohl(rpkt->exten[exten_words_used]);
		get_key(key_id, &pkt_key);
		if (!pkt_key) {
			printf("unrecognized key ID = 0x%08x\n", key_id);
			break;
		}
		/* Seems like we've got a key with matching keyid */
		/* Generate a md5sum of the packet with the key from our keyfile
		 * and compare those md5sums */
		mac_size = exten_words << 2;
		if (!auth_md5((char *)rpkt, pkt_len - mac_size, mac_size - 4, pkt_key)) {
			break;
		}
		/* Yay! Things worked out! */
		if (ENABLED_OPT(NORMALVERBOSE)) {
			char *hostname = ss_to_str(sas);
			printf("sntp %s: packet received from %s successfully authenticated using key id %i.\n",
				func_name, hostname, key_id);
			free(hostname);
		}
		is_authentic = 1;
		break;
	case 0:
		break;
	default:
		goto unusable;
		break;
	}
	if (!is_authentic) {
		if (ENABLED_OPT(AUTHENTICATION)) {
			/* We want a authenticated packet */
			if (ENABLED_OPT(NORMALVERBOSE)) {
				char *hostname = ss_to_str(sas);
				printf("sntp %s: packet received from %s is not authentic. Will discard it.\n",
					func_name, hostname);
				free(hostname);
			}
			return SERVER_AUTH_FAIL;
		}
		/* We don't know if the user wanted authentication so let's 
		 * use it anyways */
		if (ENABLED_OPT(NORMALVERBOSE)) {
			char *hostname = ss_to_str(sas);
			printf("sntp %s: packet received from %s is not authentic. Authentication not enforced.\n",
				func_name, hostname);
			free(hostname);
		}
	}
	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Packet shows wrong version (%i)\n",
				func_name, PKT_VERSION(rpkt->li_vn_mode));
		return SERVER_UNUSEABLE;
	} 
	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: mode %d stratum %i\n", func_name, 
			       PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
		return SERVER_UNUSEABLE;
	}
	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Stratum unspecified, going to check for KOD (stratum: %i)\n", 
				func_name, rpkt->stratum);
		ref_char = (char *) &rpkt->refid;
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp %s: Packet refid: %c%c%c%c\n", func_name,
			       ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (strncmp(ref_char, "DENY", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RSTR", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RATE", 4) == 0)
				return KOD_RATE;
			/* There are other interesting kiss codes which might be interesting for authentication */
		}
	}
	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp %s: Server not in sync, skipping this server\n", func_name);
		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request, but only if we're not in broadcast mode.
	 */
#ifdef DEBUG
	printf("rpkt->org:\n");
	l_fp_output(&rpkt->org, stdout);
	printf("spkt->xmt:\n");
	l_fp_output(&spkt->xmt, stdout);
#endif
	if (mode != MODE_BROADCAST && !L_ISEQU(&rpkt->org, &spkt->xmt)) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp process_pkt: pkt.org and peer.xmt differ\n");
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}
Example #7
0
/*
** Check if it's data for us and whether it's useable or not.
**
** If not, return a failure code so we can delete this server from our list
** and continue with another one.
*/
int
process_pkt (
	struct pkt *rpkt,
	sockaddr_u *sender,
	int pkt_len,
	int mode,
	struct pkt *spkt,
	const char * func_name
	)
{
	u_int		key_id;
	struct key *	pkt_key;
	int		is_authentic;
	int		mac_size;
	u_int		exten_len;
	u_int32 *       exten_end;
	u_int32 *       packet_end;
	l_fp		sent_xmt;
	l_fp		resp_org;

	// key_id = 0;
	pkt_key = NULL;
	is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;

	/*
	 * Parse the extension field if present. We figure out whether
	 * an extension field is present by measuring the MAC size. If
	 * the number of words following the packet header is 0, no MAC
	 * is present and the packet is not authenticated. If 1, the
	 * packet is a crypto-NAK; if 3, the packet is authenticated
	 * with DES; if 5, the packet is authenticated with MD5; if 6,
	 * the packet is authenticated with SHA. If 2 or 4, the packet
	 * is a runt and discarded forthwith. If greater than 6, an
	 * extension field is present, so we subtract the length of the
	 * field and go around again.
	 */
	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
		msyslog(LOG_ERR,
			"%s: Incredible packet length: %d.  Discarding.",
			func_name, pkt_len);
		return PACKET_UNUSEABLE;
	}

	/* HMS: the following needs a bit of work */
	/* Note: pkt_len must be a multiple of 4 at this point! */
	packet_end = (void*)((char*)rpkt + pkt_len);
	exten_end = skip_efields(rpkt->exten, packet_end);
	if (NULL == exten_end) {
		msyslog(LOG_ERR,
			"%s: Missing extension field.  Discarding.",
			func_name);
		return PACKET_UNUSEABLE;
	}

	/* get size of MAC in cells; can be zero */
	exten_len = (u_int)(packet_end - exten_end);

	/* deduce action required from remaining length */
	switch (exten_len) {

	case 0:	/* no Legacy MAC */
		break;

	case 1:	/* crypto NAK */		
		/* Only if the keyID is 0 and there were no EFs */
		key_id = ntohl(*exten_end);
		printf("Crypto NAK = 0x%08x from %s\n", key_id, stoa(sender));
		break;

	case 3: /* key ID + 3DES MAC -- unsupported! */
		msyslog(LOG_ERR,
			"%s: Key ID + 3DES MAC is unsupported.  Discarding.",
			func_name);
		return PACKET_UNUSEABLE;

	case 5:	/* key ID + MD5 MAC */
	case 6:	/* key ID + SHA MAC */
		/*
		** Look for the key used by the server in the specified
		** keyfile and if existent, fetch it or else leave the
		** pointer untouched
		*/
		key_id = ntohl(*exten_end);
		get_key(key_id, &pkt_key);
		if (!pkt_key) {
			printf("unrecognized key ID = 0x%08x\n", key_id);
			break;
		}
		/*
		** Seems like we've got a key with matching keyid.
		**
		** Generate a md5sum of the packet with the key from our
		** keyfile and compare those md5sums.
		*/
		mac_size = exten_len << 2;
		if (!auth_md5(rpkt, pkt_len - mac_size,
			      mac_size - 4, pkt_key)) {
			is_authentic = FALSE;
			break;
		}
		/* Yay! Things worked out! */
		is_authentic = TRUE;
		TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
			  func_name, stoa(sender), key_id));
		break;

	default:
		msyslog(LOG_ERR,
			"%s: Unexpected extension length: %d.  Discarding.",
			func_name, exten_len);
		return PACKET_UNUSEABLE;
	}

	switch (is_authentic) {

	case -1:	/* unknown */
		break;

	case 0:		/* not authentic */
		return SERVER_AUTH_FAIL;
		break;

	case 1:		/* authentic */
		break;

	default:	/* error */
		break;
	}

	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		msyslog(LOG_ERR,
			"%s: Packet shows wrong version (%d)",
			func_name, PKT_VERSION(rpkt->li_vn_mode));
		return SERVER_UNUSEABLE;
	} 
	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		msyslog(LOG_ERR,
			"%s: mode %d stratum %d", func_name, 
			PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
		return SERVER_UNUSEABLE;
	}
	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;

		TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 
			  func_name, rpkt->stratum));
		ref_char = (char *) &rpkt->refid;
		TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
			  ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (strncmp(ref_char, "DENY", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RSTR", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RATE", 4) == 0)
				return KOD_RATE;
			/*
			** There are other interesting kiss codes which
			** might be interesting for authentication.
			*/
		}
	}
	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		msyslog(LOG_ERR,
			"%s: %s not in sync, skipping this server",
			func_name, stoa(sender));
		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request, but only if we're not in broadcast mode.
	 */
	if (MODE_BROADCAST == mode)
		return pkt_len;

	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
		NTOHL_FP(&rpkt->org, &resp_org);
		NTOHL_FP(&spkt->xmt, &sent_xmt);
		msyslog(LOG_ERR,
			"%s response org expected to match sent xmt",
			stoa(sender));
		msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
		msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}
Example #8
0
/* Fetch data, check if it's data for us and whether it's useable or not. If not, return 
 * a failure code so we can delete this server from our list and continue with another one. 
 */
int 
recvpkt (
		SOCKET rsock,
		struct pkt *rpkt,
		struct pkt *spkt
	)
{
	sockaddr_u sender;
	char *rdata /* , done */;

	register int a;
	int has_mac, is_authentic, pkt_len, orig_pkt_len;


	/* Much space, just to be sure */
	rdata = emalloc(sizeof(char) * 256);

	pkt_len = recvdata(rsock, &sender, rdata, 256);

#if 0	/* done uninitialized */
	if (!done) {
		/* Do something about it, first check for a maximum length of ntp packets,
		 * probably that's something we can avoid 
		 */
	}
#endif
	
	if (pkt_len < 0) {
		if (ENABLED_OPT(NORMALVERBOSE)) {
			printf("sntp recvpkt failed: %d.\n", pkt_len);
		}
		free(rdata);
		return pkt_len;
	}
	
	/* Some checks to see if that packet is intended for us */

	/* No MAC, no authentication */
	if (LEN_PKT_NOMAC == pkt_len)
		has_mac = 0;

	/* If there's more than just the NTP packet it should be a MAC */	
	else if (pkt_len > LEN_PKT_NOMAC) 
		has_mac = pkt_len - LEN_PKT_NOMAC;
	
	else {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Funny packet length: %i. Discarding package.\n", pkt_len);
		free(rdata);

		return PACKET_UNUSEABLE;
	}

	/* Packet too big */
	if (pkt_len > LEN_PKT_MAC) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Received packet is too big (%i bytes), trying again to get a useable packet\n", 
					pkt_len);
		free(rdata);

		return PACKET_UNUSEABLE;
	}

	orig_pkt_len = pkt_len;
	pkt_len = min(pkt_len, sizeof(struct pkt));
	
	for (a = 0; a < pkt_len; a++) 
		/* FIXME! */
		if (a < orig_pkt_len)
			((char *) rpkt)[a] = rdata[a];
		else
			((char *) rpkt)[a] = 0;

	free(rdata);
	rdata = NULL;

	/* MAC could be useable for us */
	if (has_mac) {
		/* Two more things that the MAC must conform to */
		if(has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
			is_authentic = 0; /* Or should we discard this packet? */
		}
		else {
			if (MAX_MAC_LEN == has_mac) {
				struct key *pkt_key = NULL;
				
				/*
				 * Look for the key used by the server in the specified keyfile
				 * and if existent, fetch it or else leave the pointer untouched 
				 */
				get_key(rpkt->mac[0], &pkt_key);

				/* Seems like we've got a key with matching keyid */
				if (pkt_key != NULL) {
					/*
					 * Generate a md5sum of the packet with the key from our keyfile
					 * and compare those md5sums 
					 */
					if (!auth_md5((char *) rpkt, has_mac, pkt_key)) {
						if (ENABLED_OPT(AUTHENTICATION)) {
							/* We want a authenticated packet */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(&sender);
								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n", 
										hostname);

								free(hostname);
							}
							return SERVER_AUTH_FAIL;
						}
						else {
							/* 
							 * We don't know if the user wanted authentication so let's 
							 * use it anyways 
							 */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(&sender);
								printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n", 
										hostname);

								free(hostname);
							}

							is_authentic = 0;
						}
					}
					else {
						/* Yay! Things worked out! */
						if (ENABLED_OPT(NORMALVERBOSE)) {
							char *hostname = ss_to_str(&sender);
							printf("sntp recvpkt: Broadcast packet received from %s successfully authenticated using key id %i.\n", 
									hostname, rpkt->mac[0]);

							free(hostname);
						}

						is_authentic = 1;
					}
				}
			}
		}
	}

	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
	    PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Packet got wrong version (%i)\n", PKT_VERSION(rpkt->li_vn_mode));

		return SERVER_UNUSEABLE;
	} 

	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: mode %d stratum %i\n",
			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);

		return SERVER_UNUSEABLE;
	}

	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;

		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);


		ref_char = (char *) &rpkt->refid;

		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp recvpkt: Packet refid: %c%c%c%c\n", ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
		
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (!strncmp(ref_char, "DENY", 4))
				return KOD_DEMOBILIZE;

			if (!strncmp(ref_char, "RSTR", 4))
				return KOD_DEMOBILIZE;

			if (!strncmp(ref_char, "RATE", 4))
				return KOD_RATE;

			/* There are other interesting kiss codes which might be interesting for authentication */
		}
	}

	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("sntp recvpkt: Server not in sync, skipping this server\n");

		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request. 
	 */

#ifdef DEBUG
	printf("rpkt->org:\n");
	l_fp_output(&rpkt->org, stdout);
	printf("spkt->xmt:\n");
	l_fp_output(&spkt->xmt, stdout);
#endif
	
	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recvpkt: pkt.org and peer.xmt differ\n");
		
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}
Example #9
0
int 
recv_bcst_pkt (
		SOCKET rsock,
		struct pkt *rpkt,
		sockaddr_u *sas
		)
{
	sockaddr_u sender;
	register int a;
	int is_authentic, has_mac = 0, orig_pkt_len;

	char *rdata = emalloc(sizeof(char) * 256);

	int pkt_len = recv_bcst_data(rsock, rdata, 256, sas, &sender);


	if (pkt_len < 0) {
		free(rdata);

		return BROADCAST_FAILED;
	}

	/* No MAC, no authentication */
	if (LEN_PKT_NOMAC == pkt_len)
		has_mac = 0;

	/* If there's more than just the NTP packet it should be a MAC */	
	else if(pkt_len > LEN_PKT_NOMAC) 
		has_mac = pkt_len - LEN_PKT_NOMAC;
	else
		if(ENABLED_OPT(NORMALVERBOSE)) {
			printf("sntp recv_bcst_pkt: Funny packet length: %i. Discarding package.\n", pkt_len);
			free(rdata);

			return PACKET_UNUSEABLE;
		}

	/* Packet too big */
	if(pkt_len > LEN_PKT_NOMAC + MAX_MAC_LEN) {
		if(ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_pkt: Received packet is too big (%i bytes), trying again to get a useFable packet\n", 
					pkt_len);
		free(rdata);

		return PACKET_UNUSEABLE;
	}
	
	orig_pkt_len = pkt_len;
	pkt_len = min(pkt_len, sizeof(struct pkt));

	/* Let's copy the received data to the packet structure */
	for (a = 0; a < pkt_len; a++) 
		if (a < orig_pkt_len)
			((char *)rpkt)[a] = rdata[a];
		else
			((char *)rpkt)[a] = 0;

	free(rdata);

	/* MAC could be useable for us */
	if (has_mac) {
		/* Two more things that the MAC must conform to */
		if (has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
			is_authentic = 0; /* Or should we discard this packet? */
		}
		else  {
			if (MAX_MAC_LEN == has_mac) {
				struct key *pkt_key = NULL;

				/* Look for the key used by the server in the specified keyfile
				 * and if existent, fetch it or else leave the pointer untouched */
				get_key(rpkt->mac[0], &pkt_key);

				/* Seems like we've got a key with matching keyid */
				if (pkt_key != NULL) {
					/* Generate a md5sum of the packet with the key from our keyfile
					 * and compare those md5sums */
					if (!auth_md5((char *) rpkt, has_mac, pkt_key)) {
						if (ENABLED_OPT(AUTHENTICATION)) {
							/* We want a authenticated packet */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(sas);
								printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n", 
										hostname);

								free(hostname);
							}
							return SERVER_AUTH_FAIL;
						}
						else {
							/* We don't know if the user wanted authentication so let's 
							 * use it anyways */
							if (ENABLED_OPT(NORMALVERBOSE)) {
								char *hostname = ss_to_str(sas);
								printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n", 
										hostname);

								free(hostname);
							}

							is_authentic = 0;
						}
					}
					else {
						/* Yay! Things worked out! */
						if (ENABLED_OPT(NORMALVERBOSE)) {
							char *hostname = ss_to_str(sas);
							printf("sntp recv_bcst_pkt: Broadcast packet received from %s successfully authenticated using key id %i.\n", 
									hostname, rpkt->mac[0]);

							free(hostname);
						}

						is_authentic = 1;
					}
				}
			}
		}
	}

	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_pkt: Packet shows wrong version (%i)\n", 
					PKT_VERSION(rpkt->li_vn_mode));

		return SERVER_UNUSEABLE;
	} 

	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != MODE_BROADCAST
		 && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_pkt: mode %d stratum %i\n",
			   PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);

		return SERVER_UNUSEABLE;
	}

	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;

		if (ENABLED_OPT(NORMALVERBOSE))
			printf("sntp recv_bcst_pkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);

		ref_char = (char *) &rpkt->refid;
		
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (strncmp(ref_char, "DENY", 4))
				return KOD_DEMOBILIZE;

			if (strncmp(ref_char, "RSTR", 4))
				return KOD_DEMOBILIZE;

			if (strncmp(ref_char, "RATE", 4))
				return KOD_RATE;

			/* There are other interesting kiss codes which might be interesting for authentication */
		}
	}

	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		if (ENABLED_OPT(NORMALVERBOSE)) 
			printf("recv_bcst_pkt: Server not in sync, skipping this server\n");

		return SERVER_UNUSEABLE;
	}

	return pkt_len;
}