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