1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright (C) 2018-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <config.h>

#include <dhcp/dhcp6.h>
#include <dhcp/option.h>
#include <dhcp/option6_auth.h>
#include <util/buffer.h>

#include <gtest/gtest.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <boost/scoped_ptr.hpp><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <iostream><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <sstream><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::util;
using boost::scoped_ptr;

namespace {
class Option6AuthTest : public ::testing::Test {
public:
    Option6AuthTest(): buff_(28) { 
    }
    OptionBuffer buff_;
};

// check constructor, setters and getters 
TEST_F(Option6AuthTest, basic) { <--- syntax error

    scoped_ptr<Option6Auth> auth; 
    ASSERT_NO_THROW(auth.reset(new Option6Auth(1,2,0,0x9000,{'a','b','c','d'})));

    ASSERT_EQ(1, auth->getProtocol());
    ASSERT_EQ(2, auth->getHashAlgo());
    ASSERT_EQ(0, auth->getReplyDetectionMethod());
    ASSERT_EQ(0x9000, auth->getReplyDetectionValue());
    
    std::vector<uint8_t> test_buf = {'a','b','c','d'};
    ASSERT_EQ(test_buf, auth->getAuthInfo());

    auth->setProtocol(2);
    auth->setHashAlgo(3);
    auth->setReplyDetectionMethod(1);
    auth->setReplyDetectionValue(109034830);
    auth->setAuthInfo({1,2,3,4});

    ASSERT_EQ(2, auth->getProtocol());
    ASSERT_EQ(3, auth->getHashAlgo());
    ASSERT_EQ(1, auth->getReplyDetectionMethod());
    ASSERT_EQ(109034830, auth->getReplyDetectionValue());
    
    test_buf = {1,2,3,4};
    ASSERT_EQ(test_buf, auth->getAuthInfo());
}

//Check if all the fields are properly parsed and stored
// todo define userdefined literal and add packing function to it
TEST_F(Option6AuthTest, parseFields) { 
    buff_[0] = 0xa1; //protocol
    buff_[1] = 0xa2; //algo
    buff_[2] = 0xa3; //rdm method
    buff_[3] = 0xa4; //rdm value
    buff_[4] = 0xa5; //rdm value
    buff_[5] = 0xa6; //rdm value
    buff_[6] = 0xa7; //rdm value
    buff_[7] = 0xa8; //rdm value
    buff_[8] = 0xa9; //rdm value
    buff_[9] = 0xaa; //rdm value
    buff_[10] = 0xab; //rdm value
    for (uint8_t i = 11; i < 27; i++) {
        buff_[i] = 0xa8; //auth info 16 bytes
    }

    scoped_ptr<Option6Auth> auth;
    auth.reset(new Option6Auth(1,2,0,9000,{'a','b','c','d'}));

    auth->unpack(buff_.begin(), buff_.begin()+27); //26 element is 16 byte offset from 10
    
    std::vector<uint8_t> test_buf(16,0xa8);
    ASSERT_EQ(0xa1, auth->getProtocol());
    ASSERT_EQ(0xa2, auth->getHashAlgo());
    ASSERT_EQ(0xa3, auth->getReplyDetectionMethod());
    ASSERT_EQ(0xa4a5a6a7a8a9aaab, auth->getReplyDetectionValue());
    ASSERT_EQ(test_buf, auth->getAuthInfo());
}

//Check of the options are correctly packed and set
TEST_F(Option6AuthTest, setFields) {
    scoped_ptr<Option6Auth> auth;
    std::vector<uint8_t> test_buf(16,0xa8);
    auth.reset(new Option6Auth(1,2,0,0x0090000000000000,test_buf));
    
    isc::util::OutputBuffer buf(31);//4 header + fixed 11 and key 16
    ASSERT_NO_THROW(auth->pack(buf));

    const uint8_t ref_data[] = {
        0, 11, 0, 27, 1, 2, 0, //header , proto algo method
        0, 0x90, 0, 0, 0, 0, 0, 0, //64 bit rdm field
        0xa8, 0xa8, 0xa8, 0xa8, //128 bits/16 byte key
        0xa8, 0xa8, 0xa8, 0xa8,
        0xa8, 0xa8, 0xa8, 0xa8,
        0xa8, 0xa8, 0xa8, 0xa8
    };
    //first check if they are of equal size
    ASSERT_EQ(buf.getLength(), sizeof(ref_data));

    //evaluate the contents of the option byte by byte
    ASSERT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
}

TEST_F(Option6AuthTest, checkHashInput) {
    scoped_ptr<Option6Auth> auth;
    
    std::vector<uint8_t> test_buf(16,0xa8);
    std::vector<uint8_t> hash_op(16,0x00);
    auth.reset(new Option6Auth(1,2,0,0x0102030405060708,test_buf));

    isc::util::OutputBuffer buf(31); 
    ASSERT_NO_THROW(auth->packHashInput(buf));
   //auth info must be 0 for calculating the checksum
    const uint8_t ref_data[] = {
        0, 11, 0, 27, 1, 2, 0, //header , proto algo method
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, //64 bit rdm field
        0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
        0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
        0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
        0x00, 0x00, 0x00, 0x00, //128 bits/16 byte key
    };
    //first check if they are of equal size
    ASSERT_EQ(buf.getLength(), sizeof(ref_data));

    //evaluate the contents of the option byte by byte
    ASSERT_EQ(0, memcmp(ref_data, buf.getData(), buf.getLength()));
}

TEST_F(Option6AuthTest, negativeCase) {
     scoped_ptr<Option6Auth> auth;

     std::vector<uint8_t> test_buf(16,0xa8);
     auth.reset(new Option6Auth(1,2,0,0x0102030405060708,test_buf));
     //allocate less space to force an exception to be thrown
     isc::util::OutputBuffer buf(20);

     ASSERT_THROW(auth->pack(buf), isc::OutOfRange);
     ASSERT_THROW(auth->packHashInput(buf), isc::OutOfRange);
}

// Checks whether the to text conversion is working ok.
TEST_F(Option6AuthTest, toText) {
    scoped_ptr<Option6Auth> auth;
    auth.reset(new Option6Auth(1,2,0,9000,{'a','b','c','d'}));

    string exp_txt = "  protocol=1, algorithm=2, rdm method=0, rdm value=9000, value=61626364";

    std::cout << auth->toText(2) << std::endl;

}

} //end namespace