1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * dhcpcd_test.cpp - unit tests for dhcpcd 17 */ 18 19 #include <stdint.h> 20 #include <stdlib.h> 21 #include <string> 22 23 #include <gtest/gtest.h> 24 25 // For convenience. 26 #define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0]) 27 28 // Regrettably, copy these defines and the dhcp_message structure in from 29 // dhcp.h. This header file is not easily included, since subsequent 30 // includes use C++ reserved keywords (like "new") as structure member names. 31 extern "C" { 32 33 #define DHO_PAD 0 34 #define DHO_DNSDOMAIN 15 35 36 /* Max MTU - defines dhcp option length */ 37 #define MTU_MAX 1500 38 39 /* Sizes for DHCP options */ 40 #define DHCP_CHADDR_LEN 16 41 #define SERVERNAME_LEN 64 42 #define BOOTFILE_LEN 128 43 #define DHCP_UDP_LEN (14 + 20 + 8) 44 #define DHCP_FIXED_LEN (DHCP_UDP_LEN + 226) 45 #define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN) 46 47 /* Some crappy DHCP servers require the BOOTP minimum length */ 48 #define BOOTP_MESSAGE_LENTH_MIN 300 49 50 struct dhcp_message { 51 uint8_t op; /* message type */ 52 uint8_t hwtype; /* hardware address type */ 53 uint8_t hwlen; /* hardware address length */ 54 uint8_t hwopcount; /* should be zero in client message */ 55 uint32_t xid; /* transaction id */ 56 uint16_t secs; /* elapsed time in sec. from boot */ 57 uint16_t flags; 58 uint32_t ciaddr; /* (previously allocated) client IP */ 59 uint32_t yiaddr; /* 'your' client IP address */ 60 uint32_t siaddr; /* should be zero in client's messages */ 61 uint32_t giaddr; /* should be zero in client's messages */ 62 uint8_t chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ 63 uint8_t servername[SERVERNAME_LEN]; /* server host name */ 64 uint8_t bootfile[BOOTFILE_LEN]; /* boot file name */ 65 uint32_t cookie; 66 uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */ 67 } _packed; 68 69 char * get_option_string(const struct dhcp_message *dhcp, uint8_t option); 70 71 } 72 73 74 static const char kOptionString[] = "hostname"; 75 76 class DhcpcdGetOptionTest : public ::testing::Test { 77 protected: 78 virtual void SetUp() { 79 memset(dhcpmsgs, 0, ARRAYSIZE(dhcpmsgs) * sizeof(struct dhcp_message)); 80 // Technically redundant. 81 memset(&(dhcpmsgs[0].options), DHO_PAD, sizeof(dhcpmsgs[0].options)); 82 83 type_index = 0; 84 length_index = 0; 85 value_index = 0; 86 } 87 88 void PopulateTLV() { 89 // May very well write off the end of the first struct dhcp_message, 90 // by design. 91 length_index = type_index + 1; 92 value_index = length_index + 1; 93 dhcpmsgs[0].options[type_index] = DHO_DNSDOMAIN; 94 dhcpmsgs[0].options[length_index] = strlen(kOptionString); 95 memcpy(&(dhcpmsgs[0].options[value_index]), 96 kOptionString, strlen(kOptionString)); 97 } 98 99 struct dhcp_message dhcpmsgs[2]; 100 size_t type_index; 101 size_t length_index; 102 size_t value_index; 103 }; 104 105 TEST_F(DhcpcdGetOptionTest, OptionNotPresent) { 106 // An entire option block of padding (all zeros). 107 EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); 108 } 109 110 TEST_F(DhcpcdGetOptionTest, TypeIsOffTheEnd) { 111 type_index = sizeof(dhcpmsgs[0].options); 112 PopulateTLV(); 113 EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); 114 } 115 116 TEST_F(DhcpcdGetOptionTest, LengthIsOffTheEnd) { 117 type_index = sizeof(dhcpmsgs[0].options) - 1; 118 PopulateTLV(); 119 EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); 120 } 121 122 TEST_F(DhcpcdGetOptionTest, ValueIsOffTheEnd) { 123 type_index = sizeof(dhcpmsgs[0].options) - 2; 124 PopulateTLV(); 125 EXPECT_EQ(NULL, ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN)); 126 } 127 128 TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForValue) { 129 type_index = sizeof(dhcpmsgs[0].options) - 6; 130 PopulateTLV(); 131 char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN); 132 EXPECT_TRUE(NULL != value); 133 EXPECT_EQ("host", ::std::string(value)); 134 free(value); 135 } 136 137 TEST_F(DhcpcdGetOptionTest, InsufficientSpaceForContinuedValue) { 138 type_index = sizeof(dhcpmsgs[0].options) - 16; 139 PopulateTLV(); 140 type_index = sizeof(dhcpmsgs[0].options) - 6; 141 PopulateTLV(); 142 char* value = ::get_option_string(&(dhcpmsgs[0]), DHO_DNSDOMAIN); 143 EXPECT_TRUE(NULL != value); 144 EXPECT_EQ("hostnamehost", ::std::string(value)); 145 free(value); 146 } 147