/* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * dhcpcd_test.cpp - unit tests for dhcpcd */ #include #include #include #include // For convenience. #define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0]) // Regrettably, copy these defines and the dhcp_message structure in from // dhcp.h. This header file is not easily included, since subsequent // includes use C++ reserved keywords (like "new") as structure member names. extern "C" { #define DHO_PAD 0 #define DHO_DNSDOMAIN 15 /* Max MTU - defines dhcp option length */ #define MTU_MAX 1500 /* Sizes for DHCP options */ #define DHCP_CHADDR_LEN 16 #define SERVERNAME_LEN 64 #define BOOTFILE_LEN 128 #define DHCP_UDP_LEN (14 + 20 + 8) #define DHCP_FIXED_LEN (DHCP_UDP_LEN + 226) #define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN) /* Some crappy DHCP servers require the BOOTP minimum length */ #define BOOTP_MESSAGE_LENTH_MIN 300 struct dhcp_message { uint8_t op; /* message type */ uint8_t hwtype; /* hardware address type */ uint8_t hwlen; /* hardware address length */ uint8_t hwopcount; /* should be zero in client message */ uint32_t xid; /* transaction id */ uint16_t secs; /* elapsed time in sec. from boot */ uint16_t flags; uint32_t ciaddr; /* (previously allocated) client IP */ uint32_t yiaddr; /* 'your' client IP address */ uint32_t siaddr; /* should be zero in client's messages */ uint32_t giaddr; /* should be zero in client's messages */ uint8_t chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ uint8_t servername[SERVERNAME_LEN]; /* server host name */ uint8_t bootfile[BOOTFILE_LEN]; /* boot file name */ uint32_t cookie; uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */ } _packed; char * get_option_string(const struct dhcp_message *dhcp, uint8_t option); } static const char kOptionString[] = "hostname"; class DhcpcdGetOptionTest : public ::testing::Test { protected: virtual void SetUp() { memset(dhcpmsgs, 0, ARRAYSIZE(dhcpmsgs) * sizeof(struct dhcp_message)); // Technically redundant. memset(&(dhcpmsgs[0].options), DHO_PAD, sizeof(dhcpmsgs[0].options)); type_index = 0; length_index = 0; value_index = 0; } void PopulateTLV() { // May very well write off the end of the first struct dhcp_message, // by design. length_index = type_index + 1; value_index = length_index + 1; dhcpmsgs[0].options[type_index] = DHO_DNSDOMAIN; dhcpmsgs[0].options[length_index] = strlen(kOptionString); memcpy(&(dhcpmsgs[0].options[value_index]), kOptionString, strlen(kOptionString)); } struct dhcp_message dhcpmsgs[2]; size_t type_index; size_t length_index; size_t value_index; }; TEST_F(DhcpcdGetOptionTest, OptionNotPresent) { // An entire option block of padding (all zeros). EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); } TEST_F(DhcpcdGetOptionTest, TypeIsOffTheEnd) { type_index = sizeof(dhcpmsgs[0].options); PopulateTLV(); EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); } TEST_F(DhcpcdGetOptionTest, LengthIsOffTheEnd) { type_index = sizeof(dhcpmsgs[0].options) - 1; PopulateTLV(); EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); } TEST_F(DhcpcdGetOptionTest, ValueIsOffTheEnd) { type_index = sizeof(dhcpmsgs[0].options) - 2; PopulateTLV(); EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); } TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForValue) { type_index = sizeof(dhcpmsgs[0].options) - 6; PopulateTLV(); char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN); EXPECT_TRUE(NULL != value); EXPECT_EQ("host", ::std::string(value)); free(value); } TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForContinuedValue) { type_index = sizeof(dhcpmsgs[0].options) - 16; PopulateTLV(); type_index = sizeof(dhcpmsgs[0].options) - 6; PopulateTLV(); char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN); EXPECT_TRUE(NULL != value); EXPECT_EQ("hostnamehost", ::std::string(value)); free(value); }