#include "g_sntptest.h" extern "C" { #include "networking.h" #include "ntp_stdlib.h" }; #include #include // Hacks into the key database. extern key* key_ptr; extern int key_cnt; class packetProcessingTest : public sntptest { protected: pkt testpkt; pkt testspkt; sockaddr_u testsock; bool restoreKeyDb; void PrepareAuthenticationTest(int key_id, int key_len, const char* type, const void* key_seq) { std::stringstream ss; ss << key_id; ActivateOption("-a", ss.str().c_str()); key_cnt = 1; key_ptr = new key; key_ptr->next = NULL; key_ptr->key_id = key_id; key_ptr->key_len = key_len; memcpy(key_ptr->type, "MD5", 3); ASSERT_TRUE(key_len < sizeof(key_ptr->key_seq)); memcpy(key_ptr->key_seq, key_seq, key_ptr->key_len); restoreKeyDb = true; } void PrepareAuthenticationTest(int key_id, int key_len, const void* key_seq) { PrepareAuthenticationTest(key_id, key_len, "MD5", key_seq); } virtual void SetUp() { restoreKeyDb = false; /* Initialize the test packet and socket, * so they contain at least some valid data. */ testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, MODE_SERVER); testpkt.stratum = STRATUM_REFCLOCK; memcpy(&testpkt.refid, "GPS\0", 4); /* Set the origin timestamp of the received packet to the * same value as the transmit timestamp of the sent packet. */ l_fp tmp; tmp.l_ui = 1000UL; tmp.l_uf = 0UL; HTONL_FP(&tmp, &testpkt.org); HTONL_FP(&tmp, &testspkt.xmt); } virtual void TearDown() { if (restoreKeyDb) { key_cnt = 0; delete key_ptr; key_ptr = NULL; } } }; TEST_F(packetProcessingTest, TooShortLength) { EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC - 1, MODE_SERVER, &testspkt, "UnitTest")); EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC - 1, MODE_BROADCAST, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, LengthNotMultipleOfFour) { EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC + 6, MODE_SERVER, &testspkt, "UnitTest")); EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC + 3, MODE_BROADCAST, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, TooShortExtensionFieldLength) { /* The lower 16-bits are the length of the extension field. * This lengths must be multiples of 4 bytes, which gives * a minimum of 4 byte extension field length. */ testpkt.exten[7] = htonl(3); // 3 bytes is too short. /* We send in a pkt_len of header size + 4 byte extension * header + 24 byte MAC, this prevents the length error to * be caught at an earlier stage */ int pkt_len = LEN_PKT_NOMAC + 4 + 24; EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, UnauthenticatedPacketReject) { // Activate authentication option ActivateOption("-a", "123"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); int pkt_len = LEN_PKT_NOMAC; // We demand authentication, but no MAC header is present. EXPECT_EQ(SERVER_AUTH_FAIL, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, CryptoNAKPacketReject) { // Activate authentication option ActivateOption("-a", "123"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); int pkt_len = LEN_PKT_NOMAC + 4; // + 4 byte MAC = Crypto-NAK EXPECT_EQ(SERVER_AUTH_FAIL, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, AuthenticatedPacketInvalid) { // Activate authentication option PrepareAuthenticationTest(50, 9, "123456789"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); // Prepare the packet. int pkt_len = LEN_PKT_NOMAC; testpkt.exten[0] = htonl(50); int mac_len = make_mac((char*)&testpkt, pkt_len, MAX_MD5_LEN, key_ptr, (char*)&testpkt.exten[1]); pkt_len += 4 + mac_len; // Now, alter the MAC so it becomes invalid. testpkt.exten[1] += 1; EXPECT_EQ(SERVER_AUTH_FAIL, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, AuthenticatedPacketUnknownKey) { // Activate authentication option PrepareAuthenticationTest(30, 9, "123456789"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); // Prepare the packet. Observe that the Key-ID expected is 30, // but the packet has a key id of 50. int pkt_len = LEN_PKT_NOMAC; testpkt.exten[0] = htonl(50); int mac_len = make_mac((char*)&testpkt, pkt_len, MAX_MD5_LEN, key_ptr, (char*)&testpkt.exten[1]); pkt_len += 4 + mac_len; EXPECT_EQ(SERVER_AUTH_FAIL, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, ServerVersionTooOld) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_OLDVERSION - 1, MODE_CLIENT); ASSERT_LT(PKT_VERSION(testpkt.li_vn_mode), NTP_OLDVERSION); int pkt_len = LEN_PKT_NOMAC; EXPECT_EQ(SERVER_UNUSEABLE, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, ServerVersionTooNew) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION + 1, MODE_CLIENT); ASSERT_GT(PKT_VERSION(testpkt.li_vn_mode), NTP_VERSION); int pkt_len = LEN_PKT_NOMAC; EXPECT_EQ(SERVER_UNUSEABLE, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, NonWantedMode) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, MODE_CLIENT); // The packet has a mode of MODE_CLIENT, but process_pkt expects MODE_SERVER EXPECT_EQ(SERVER_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } /* Tests bug 1597 */ TEST_F(packetProcessingTest, KoDRate) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.stratum = STRATUM_PKT_UNSPEC; memcpy(&testpkt.refid, "RATE", 4); EXPECT_EQ(KOD_RATE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, KoDDeny) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.stratum = STRATUM_PKT_UNSPEC; memcpy(&testpkt.refid, "DENY", 4); EXPECT_EQ(KOD_DEMOBILIZE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, RejectUnsyncedServer) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOTINSYNC, NTP_VERSION, MODE_SERVER); EXPECT_EQ(SERVER_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, RejectWrongResponseServerMode) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); l_fp tmp; tmp.l_ui = 1000UL; tmp.l_uf = 0UL; HTONL_FP(&tmp, &testpkt.org); tmp.l_ui = 2000UL; tmp.l_uf = 0UL; HTONL_FP(&tmp, &testspkt.xmt); EXPECT_EQ(PACKET_UNUSEABLE, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, AcceptNoSentPacketBroadcastMode) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); testpkt.li_vn_mode = PKT_LI_VN_MODE(LEAP_NOWARNING, NTP_VERSION, MODE_BROADCAST); EXPECT_EQ(LEN_PKT_NOMAC, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_BROADCAST, NULL, "UnitTest")); } TEST_F(packetProcessingTest, CorrectUnauthenticatedPacket) { ASSERT_FALSE(ENABLED_OPT(AUTHENTICATION)); EXPECT_EQ(LEN_PKT_NOMAC, process_pkt(&testpkt, &testsock, LEN_PKT_NOMAC, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, CorrectAuthenticatedPacketMD5) { PrepareAuthenticationTest(10, 15, "123456789abcdef"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); int pkt_len = LEN_PKT_NOMAC; // Prepare the packet. testpkt.exten[0] = htonl(10); int mac_len = make_mac((char*)&testpkt, pkt_len, MAX_MD5_LEN, key_ptr, (char*)&testpkt.exten[1]); pkt_len += 4 + mac_len; EXPECT_EQ(pkt_len, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); } TEST_F(packetProcessingTest, CorrectAuthenticatedPacketSHA1) { PrepareAuthenticationTest(20, 15, "SHA1", "abcdefghijklmno"); ASSERT_TRUE(ENABLED_OPT(AUTHENTICATION)); int pkt_len = LEN_PKT_NOMAC; // Prepare the packet. testpkt.exten[0] = htonl(20); int mac_len = make_mac((char*)&testpkt, pkt_len, MAX_MAC_LEN, key_ptr, (char*)&testpkt.exten[1]); pkt_len += 4 + mac_len; EXPECT_EQ(pkt_len, process_pkt(&testpkt, &testsock, pkt_len, MODE_SERVER, &testspkt, "UnitTest")); }