Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright 2017, 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 
     17 #include "message.h"
     18 #include "dhcp.h"
     19 
     20 #include <string.h>
     21 
     22 #include <vector>
     23 
     24 static uint32_t sNextTransactionId = 1;
     25 
     26 static const ptrdiff_t kOptionOffset = 7;
     27 
     28 // The default lease time in seconds
     29 static const uint32_t kDefaultLeaseTime = 10 * 60;
     30 
     31 // The parameters that the client would like to receive from the server
     32 static const uint8_t kRequestParameters[] = { OPT_SUBNET_MASK,
     33                                               OPT_GATEWAY,
     34                                               OPT_DNS,
     35                                               OPT_BROADCAST_ADDR,
     36                                               OPT_LEASE_TIME,
     37                                               OPT_T1,
     38                                               OPT_T2,
     39                                               OPT_MTU };
     40 
     41 Message::Message() {
     42     memset(&dhcpData, 0, sizeof(dhcpData));
     43     mSize = 0;
     44 }
     45 
     46 Message::Message(const uint8_t* data, size_t size) {
     47     if (size <= sizeof(dhcpData)) {
     48         memcpy(&dhcpData, data, size);
     49         mSize = size;
     50     } else {
     51         memset(&dhcpData, 0, sizeof(dhcpData));
     52         mSize = 0;
     53     }
     54 }
     55 
     56 Message Message::discover(const uint8_t (&sourceMac)[ETH_ALEN]) {
     57     Message message(OP_BOOTREQUEST,
     58                     sourceMac,
     59                     static_cast<uint8_t>(DHCPDISCOVER));
     60 
     61     message.addOption(OPT_PARAMETER_LIST, kRequestParameters);
     62     message.endOptions();
     63 
     64     return message;
     65 }
     66 
     67 Message Message::request(const uint8_t (&sourceMac)[ETH_ALEN],
     68                          in_addr_t requestAddress,
     69                          in_addr_t serverAddress) {
     70 
     71     Message message(OP_BOOTREQUEST,
     72                     sourceMac,
     73                     static_cast<uint8_t>(DHCPREQUEST));
     74 
     75     message.addOption(OPT_PARAMETER_LIST, kRequestParameters);
     76     message.addOption(OPT_REQUESTED_IP, requestAddress);
     77     message.addOption(OPT_SERVER_ID, serverAddress);
     78     message.endOptions();
     79 
     80     return message;
     81 }
     82 
     83 Message Message::offer(const Message& sourceMessage,
     84                        in_addr_t serverAddress,
     85                        in_addr_t offeredAddress,
     86                        in_addr_t offeredNetmask,
     87                        in_addr_t offeredGateway,
     88                        const in_addr_t* offeredDnsServers,
     89                        size_t numOfferedDnsServers) {
     90 
     91     uint8_t macAddress[ETH_ALEN];
     92     memcpy(macAddress, sourceMessage.dhcpData.chaddr, sizeof(macAddress));
     93     Message message(OP_BOOTREPLY, macAddress, static_cast<uint8_t>(DHCPOFFER));
     94 
     95     message.dhcpData.xid = sourceMessage.dhcpData.xid;
     96     message.dhcpData.flags = sourceMessage.dhcpData.flags;
     97     message.dhcpData.yiaddr = offeredAddress;
     98     message.dhcpData.giaddr = sourceMessage.dhcpData.giaddr;
     99 
    100     message.addOption(OPT_SERVER_ID, serverAddress);
    101     message.addOption(OPT_LEASE_TIME, kDefaultLeaseTime);
    102     message.addOption(OPT_SUBNET_MASK, offeredNetmask);
    103     message.addOption(OPT_GATEWAY, offeredGateway);
    104     message.addOption(OPT_DNS,
    105                       offeredDnsServers,
    106                       numOfferedDnsServers * sizeof(in_addr_t));
    107 
    108     message.endOptions();
    109 
    110     return message;
    111 }
    112 
    113 Message Message::ack(const Message& sourceMessage,
    114                      in_addr_t serverAddress,
    115                      in_addr_t offeredAddress,
    116                      in_addr_t offeredNetmask,
    117                      in_addr_t offeredGateway,
    118                      const in_addr_t* offeredDnsServers,
    119                      size_t numOfferedDnsServers) {
    120     uint8_t macAddress[ETH_ALEN];
    121     memcpy(macAddress, sourceMessage.dhcpData.chaddr, sizeof(macAddress));
    122     Message message(OP_BOOTREPLY, macAddress, static_cast<uint8_t>(DHCPACK));
    123 
    124     message.dhcpData.xid = sourceMessage.dhcpData.xid;
    125     message.dhcpData.flags = sourceMessage.dhcpData.flags;
    126     message.dhcpData.yiaddr = offeredAddress;
    127     message.dhcpData.giaddr = sourceMessage.dhcpData.giaddr;
    128 
    129     message.addOption(OPT_SERVER_ID, serverAddress);
    130     message.addOption(OPT_LEASE_TIME, kDefaultLeaseTime);
    131     message.addOption(OPT_SUBNET_MASK, offeredNetmask);
    132     message.addOption(OPT_GATEWAY, offeredGateway);
    133     message.addOption(OPT_DNS,
    134                       offeredDnsServers,
    135                       numOfferedDnsServers * sizeof(in_addr_t));
    136 
    137     message.endOptions();
    138 
    139     return message;
    140 }
    141 
    142 Message Message::nack(const Message& sourceMessage, in_addr_t serverAddress) {
    143     uint8_t macAddress[ETH_ALEN];
    144     memcpy(macAddress, sourceMessage.dhcpData.chaddr, sizeof(macAddress));
    145     Message message(OP_BOOTREPLY, macAddress, static_cast<uint8_t>(DHCPNAK));
    146 
    147     message.dhcpData.xid = sourceMessage.dhcpData.xid;
    148     message.dhcpData.flags = sourceMessage.dhcpData.flags;
    149     message.dhcpData.giaddr = sourceMessage.dhcpData.giaddr;
    150 
    151     message.addOption(OPT_SERVER_ID, serverAddress);
    152     message.endOptions();
    153 
    154     return message;
    155 }
    156 
    157 bool Message::isValidDhcpMessage(uint8_t expectedOp,
    158                                  uint32_t expectedXid) const {
    159     if (!isValidDhcpMessage(expectedOp)) {
    160         return false;
    161     }
    162     // Only look for message with a matching transaction ID
    163     if (dhcpData.xid != expectedXid) {
    164         return false;
    165     }
    166     return true;
    167 }
    168 
    169 bool Message::isValidDhcpMessage(uint8_t expectedOp) const {
    170     // Require that there is at least enough options for the DHCP cookie
    171     if (dhcpData.options + 4 > end()) {
    172         return false;
    173     }
    174 
    175     if (dhcpData.op != expectedOp) {
    176         return false;
    177     }
    178     if (dhcpData.htype != HTYPE_ETHER) {
    179         return false;
    180     }
    181     if (dhcpData.hlen != ETH_ALEN) {
    182         return false;
    183     }
    184 
    185     // Need to have the correct cookie in the options
    186     if (dhcpData.options[0] != OPT_COOKIE1) {
    187         return false;
    188     }
    189     if (dhcpData.options[1] != OPT_COOKIE2) {
    190         return false;
    191     }
    192     if (dhcpData.options[2] != OPT_COOKIE3) {
    193         return false;
    194     }
    195     if (dhcpData.options[3] != OPT_COOKIE4) {
    196         return false;
    197     }
    198 
    199     return true;
    200 }
    201 
    202 size_t Message::optionsSize() const {
    203     auto options = reinterpret_cast<const uint8_t*>(&dhcpData.options);
    204     const uint8_t* msgEnd = end();
    205     if (msgEnd <= options) {
    206         return 0;
    207     }
    208     return msgEnd - options;
    209 }
    210 
    211 uint8_t Message::type() const {
    212     uint8_t length = 0;
    213     const uint8_t* opt = getOption(OPT_MESSAGE_TYPE, &length);
    214     if (opt && length == 1) {
    215         return *opt;
    216     }
    217     return 0;
    218 }
    219 
    220 in_addr_t Message::serverId() const {
    221     uint8_t length = 0;
    222     const uint8_t* opt = getOption(OPT_SERVER_ID, &length);
    223     if (opt && length == 4) {
    224         return *reinterpret_cast<const in_addr_t*>(opt);
    225     }
    226     return 0;
    227 }
    228 
    229 in_addr_t Message::requestedIp() const {
    230     uint8_t length = 0;
    231     const uint8_t* opt = getOption(OPT_REQUESTED_IP, &length);
    232     if (opt && length == 4) {
    233         return *reinterpret_cast<const in_addr_t*>(opt);
    234     }
    235     return 0;
    236 }
    237 
    238 Message::Message(uint8_t operation,
    239                  const uint8_t (&macAddress)[ETH_ALEN],
    240                  uint8_t type) {
    241     memset(&dhcpData, 0, sizeof(dhcpData));
    242 
    243     dhcpData.op = operation;
    244     dhcpData.htype = HTYPE_ETHER;
    245     dhcpData.hlen = ETH_ALEN;
    246     dhcpData.hops = 0;
    247 
    248     dhcpData.flags = htons(FLAGS_BROADCAST);
    249 
    250     dhcpData.xid = htonl(sNextTransactionId++);
    251 
    252     memcpy(dhcpData.chaddr, macAddress, ETH_ALEN);
    253 
    254     uint8_t* opts = dhcpData.options;
    255 
    256     *opts++ = OPT_COOKIE1;
    257     *opts++ = OPT_COOKIE2;
    258     *opts++ = OPT_COOKIE3;
    259     *opts++ = OPT_COOKIE4;
    260 
    261     *opts++ = OPT_MESSAGE_TYPE;
    262     *opts++ = 1;
    263     *opts++ = type;
    264 
    265     updateSize(opts);
    266 }
    267 
    268 void Message::addOption(uint8_t type, const void* data, uint8_t size) {
    269     uint8_t* opts = nextOption();
    270 
    271     *opts++ = type;
    272     *opts++ = size;
    273     memcpy(opts, data, size);
    274     opts += size;
    275 
    276     updateSize(opts);
    277 }
    278 
    279 void Message::endOptions() {
    280     uint8_t* opts = nextOption();
    281 
    282     *opts++ = OPT_END;
    283 
    284     updateSize(opts);
    285 }
    286 
    287 const uint8_t* Message::getOption(uint8_t expectedOptCode,
    288                                   uint8_t* length) const {
    289     size_t optsSize = optionsSize();
    290     for (size_t i = 4; i + 2 < optsSize; ) {
    291         uint8_t optCode = dhcpData.options[i];
    292         uint8_t optLen = dhcpData.options[i + 1];
    293         const uint8_t* opt = dhcpData.options + i + 2;
    294 
    295         if (optCode == OPT_END) {
    296             return nullptr;
    297         }
    298         if (optCode == expectedOptCode) {
    299             *length = optLen;
    300             return opt;
    301         }
    302         i += 2 + optLen;
    303     }
    304     return nullptr;
    305 }
    306 
    307 uint8_t* Message::nextOption() {
    308     return reinterpret_cast<uint8_t*>(&dhcpData) + size();
    309 }
    310 
    311 void Message::updateSize(uint8_t* optionsEnd) {
    312     mSize = optionsEnd - reinterpret_cast<uint8_t*>(&dhcpData);
    313 }
    314 
    315