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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// Copyright (C) 2012-2017 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 <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.
#include <arpa/inet.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <gtest/gtest.h><--- Include file:  not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <asiolink/io_address.h>
#include <dhcp/option.h>
#include <dhcp/dhcp6.h>

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

#include "../localized_option.h"
#include "../perf_pkt6.h"

using namespace std;
using namespace isc;
using namespace isc::dhcp;
using namespace isc::perfdhcp;

typedef PerfPkt6::LocalizedOptionPtr LocalizedOptionPtr;

namespace {

class PerfPkt6Test : public ::testing::Test {
public:
    PerfPkt6Test() {
    }

    /// \brief Returns captured SOLICIT packet.
    ///
    /// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
    /// in_na, dns-server, elapsed-time, option-request
    /// This code was autogenerated
    /// (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
    /// but we spent some time to make is less ugly than it used to be.
    ///
    /// \return pointer to Pkt6 that represents received SOLICIT
    PerfPkt6* capture() {
        uint8_t data[98];
        data[0]  = 1;
        data[1]  = 1;       data[2]  = 2;     data[3] = 3;      data[4]  = 0;
        data[5]  = 1;       data[6]  = 0;     data[7] = 14;     data[8]  = 0;
        data[9]  = 1;       data[10] = 0;     data[11] = 1;     data[12] = 21;
        data[13] = 158;     data[14] = 60;    data[15] = 22;    data[16] = 0;
        data[17] = 30;      data[18] = 140;   data[19] = 155;   data[20] = 115;
        data[21] = 73;      data[22] = 0;     data[23] = 3;     data[24] = 0;
        data[25] = 40;      data[26] = 0;     data[27] = 0;     data[28] = 0;
        data[29] = 1;       data[30] = 255;   data[31] = 255;   data[32] = 255;
        data[33] = 255;     data[34] = 255;   data[35] = 255;   data[36] = 255;
        data[37] = 255;     data[38] = 0;     data[39] = 5;     data[40] = 0;
        data[41] = 24;      data[42] = 32;    data[43] = 1;     data[44] = 13;
        data[45] = 184;     data[46] = 0;     data[47] = 1;     data[48] = 0;
        data[49] = 0;       data[50] = 0;     data[51] = 0;     data[52] = 0;
        data[53] = 0;       data[54] = 0;     data[55] = 0;     data[56] = 18;
        data[57] = 52;      data[58] = 255;   data[59] = 255;   data[60] = 255;
        data[61] = 255;     data[62] = 255;   data[63] = 255;   data[64] = 255;
        data[65] = 255;     data[66] = 0;     data[67] = 23;    data[68] = 0;
        data[69] = 16;      data[70] = 32;    data[71] = 1;     data[72] = 13;
        data[73] = 184;     data[74] = 0;     data[75] = 1;     data[76] = 0;
        data[77] = 0;       data[78] = 0;     data[79] = 0;     data[80] = 0;
        data[81] = 0;       data[82] = 0;     data[83] = 0;     data[84] = 221;
        data[85] = 221;     data[86] = 0;     data[87] = 8;     data[88] = 0;
        data[89] = 2;       data[90] = 0;     data[91] = 100;   data[92] = 0;
        data[93] = 6;       data[94] = 0;     data[95] = 2;     data[96] = 0;
        data[97] = 23;

        PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));

        return (pkt);
    }

    /// \brief Returns truncated SOLICIT packet.
    ///
    /// Returns truncated SOLICIT packet which will be used for
    /// negative tests: e.g. pack options out of packet.
    ///
    /// \return pointer to Pkt6 that represents truncated SOLICIT
    PerfPkt6* captureTruncated() {
        uint8_t data[17];
        data[0]  = 1;
        data[1]  = 1;       data[2]  = 2;     data[3] = 3;      data[4]  = 0;
        data[5]  = 1;       data[6]  = 0;     data[7] = 14;     data[8]  = 0;
        data[9]  = 1;       data[10] = 0;     data[11] = 1;     data[12] = 21;
        data[13] = 158;     data[14] = 60;    data[15] = 22;    data[16] = 0;

        PerfPkt6* pkt = new PerfPkt6(data, sizeof(data));

        return (pkt);
    }


};

TEST_F(PerfPkt6Test, Constructor) {<--- syntax error
    // Data to be used to create packet.
    uint8_t data[] = { 0, 1, 2, 3, 4, 5 };

    // Test constructor to be used for incoming messages.
    // Use default (1) offset value and don't specify transaction id.
    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data)));
    EXPECT_EQ(sizeof(data), pkt1->data_.size());
    EXPECT_EQ(0, memcmp(&pkt1->data_[0], data, sizeof(data)));
    EXPECT_EQ(1, pkt1->getTransidOffset());

    // Test constructor to be used for outgoing messages.
    // Use non-zero offset and specify transaction id.
    const size_t offset_transid = 10;
    const uint32_t transid = 0x010203;
    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data),
                                                  offset_transid, transid));
    EXPECT_EQ(sizeof(data), pkt2->data_.size());
    EXPECT_EQ(0, memcmp(&pkt2->data_[0], data, sizeof(data)));
    EXPECT_EQ(0x010203, pkt2->getTransid());
    EXPECT_EQ(10, pkt2->getTransidOffset());
}

TEST_F(PerfPkt6Test, RawPackUnpack) {
    // Create first packet.
    boost::scoped_ptr<PerfPkt6> pkt1(capture());

    // Create some input buffers to initialize options.
    uint8_t buf_elapsed_time[] = { 1, 1 };
    uint8_t buf_duid[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };

    // Create options.
    const size_t offset_elapsed_time = 86;
    OptionBuffer vec_elapsed_time(buf_elapsed_time,
                                  buf_elapsed_time + sizeof(buf_elapsed_time));
    LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6,
                                                             D6O_ELAPSED_TIME,
                                                             vec_elapsed_time,
                                                             offset_elapsed_time));
    const size_t offset_duid = 4;
    OptionBuffer vec_duid(buf_duid, buf_duid + sizeof(buf_duid));
    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
                                                     D6O_CLIENTID,
                                                     vec_duid,
                                                     offset_duid));

    // Add option to packet and create on-wire format from added options.
    // Contents of options will override contents of packet buffer.
    ASSERT_NO_THROW(pkt1->addOption(pkt1_elapsed_time));
    ASSERT_NO_THROW(pkt1->addOption(pkt1_duid));
    ASSERT_TRUE(pkt1->rawPack());

    // Reset so as we can reuse them for another packet.
    vec_elapsed_time.clear();
    vec_duid.clear();

    // Get output buffer from packet 1 to create new packet
    // that will be later validated.
    util::OutputBuffer pkt1_output = pkt1->getBuffer();
    ASSERT_EQ(pkt1_output.getLength(), pkt1->data_.size());
    const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
        (pkt1_output.getData());
    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,
                                                  pkt1_output.getLength()));

    // Create objects specifying options offset in a packet.
    // Offsets will inform pkt2 object where to read data from.
    LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6,
                                                             D6O_ELAPSED_TIME,
                                                             vec_elapsed_time,
                                                             offset_elapsed_time));
    LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6,
                                                     D6O_CLIENTID,
                                                     vec_duid,
                                                     offset_duid));
    // Add options to packet to pass their offsets.
    pkt2->addOption(pkt2_elapsed_time);
    pkt2->addOption(pkt2_duid);

    // Unpack: get relevant parts of buffer data into option objects.
    ASSERT_TRUE(pkt2->rawUnpack());

    // Once option data is stored in options objects we pull it out.
    pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>
        (pkt2->getOption(D6O_ELAPSED_TIME));
    pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>
        (pkt2->getOption(D6O_CLIENTID));

    // Check if options are present. They have to be there since
    // we have added them ourselfs.
    ASSERT_TRUE(pkt2_elapsed_time);
    ASSERT_TRUE(pkt2_duid);

    // Expecting option contents be the same as original.
    OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
    OptionBuffer pkt2_duid_data = pkt2_duid->getData();
    EXPECT_EQ(0x0101, pkt2_elapsed_time->getUint16());
    EXPECT_TRUE(std::equal(pkt2_duid_data.begin(),
                           pkt2_duid_data.end(),
                           buf_duid));
}

TEST_F(PerfPkt6Test, InvalidOptions) {
    // Create packet.
    boost::scoped_ptr<PerfPkt6> pkt1(capture());
    OptionBuffer vec_server_id;
    vec_server_id.resize(10);
    // Testing invalid offset of the option (greater than packet size)
    const size_t offset_serverid[] = { 150, 85 };
    LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6,
                                                         D6O_SERVERID,
                                                         vec_server_id,
                                                         offset_serverid[0]));
    pkt1->addOption(pkt1_serverid);
    // Pack has to fail due to invalid offset.
    EXPECT_FALSE(pkt1->rawPack());

    // Create packet.
    boost::scoped_ptr<PerfPkt6> pkt2(capture());
    // Testing offset of the option (lower than packet size but
    // tail of the option out of bounds).
    LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6,
                                                         D6O_SERVERID,
                                                         vec_server_id,
                                                         offset_serverid[1]));
    pkt2->addOption(pkt2_serverid);
    // Pack must fail due to invalid offset.
    EXPECT_FALSE(pkt2->rawPack());
}


TEST_F(PerfPkt6Test, TruncatedPacket) {
    cout << "Testing parsing options from truncated packet."
         << "This may produce spurious errors" << endl;

    // Create truncated (in the middle of duid options)
    boost::scoped_ptr<PerfPkt6> pkt1(captureTruncated());
    OptionBuffer vec_duid;
    vec_duid.resize(30);
    const size_t offset_duid = 4;
    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
                                                     D6O_CLIENTID,
                                                     vec_duid,
                                                     offset_duid));
    pkt1->addOption(pkt1_duid);
    // Pack/unpack must fail because length of the option read from buffer
    // will extend over the actual packet length.
    EXPECT_FALSE(pkt1->rawUnpack());
    EXPECT_FALSE(pkt1->rawPack());
}

TEST_F(PerfPkt6Test, PackTransactionId) {
    uint8_t data[100];
    memset(&data, 0, sizeof(data));

    const size_t offset_transid[] = { 50, 100 };
    const uint32_t transid = 0x010203;

    // Create dummy packet that is simply filled with zeros.
    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
                                                  sizeof(data),
                                                  offset_transid[0],
                                                  transid));

    // Reference data are non zero so we can detect them in dummy packet.
    uint8_t ref_data[3] = { 1, 2, 3 };

    // This will store given transaction id in the packet data at
    // offset of 50.
    ASSERT_TRUE(pkt1->rawPack());

    // Get the output buffer so we can validate it.
    util::OutputBuffer out_buf = pkt1->getBuffer();
    ASSERT_EQ(sizeof(data), out_buf.getLength());
    const uint8_t *out_buf_data = static_cast<const uint8_t*>
        (out_buf.getData());

    // Try to make clang static analyzer happy.
    ASSERT_LE(offset_transid[0], out_buf.getLength());

    // Validate transaction id.
    EXPECT_EQ(0, memcmp(ref_data, out_buf_data + offset_transid[0], 3));


    // Out of bounds transaction id offset.
    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
                                                  sizeof(data),
                                                  offset_transid[1],
                                                  transid));
    cout << "Testing out of bounds offset. "
        "This may produce spurious errors ..." << endl;
    EXPECT_FALSE(pkt2->rawPack());
}

TEST_F(PerfPkt6Test, UnpackTransactionId) {
    // Initialize data for dummy packet (zeros only).
    uint8_t data[100] = { 0 };

    // Generate transaction id = 0x010203 and inject at offset = 50.
    for (uint8_t i = 50; i <  53; ++i) {
        data[i] = i - 49;
    }
    // Create packet and point out that transaction id is at offset 50.
    const size_t offset_transid[] = { 50, 300 };
    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
                                                  sizeof(data),
                                                  offset_transid[0]));

    // Get transaction id out of buffer and store in class member.
    ASSERT_TRUE(pkt1->rawUnpack());
    // Test value of transaction id.
    EXPECT_EQ(0x010203, pkt1->getTransid());

    // Out of bounds transaction id offset.
    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
                                                  sizeof(data),
                                                  offset_transid[1]));
    cout << "Testing out of bounds offset. "
        "This may produce spurious errors ..." << endl;
    EXPECT_FALSE(pkt2->rawUnpack());

}

}