Home | History | Annotate | Download | only in dhcpcd
      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