Home | History | Annotate | Download | only in server
      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 "dhcpserver.h"
     18 
     19 #include "dhcp.h"
     20 #include "log.h"
     21 #include "message.h"
     22 
     23 #include <arpa/inet.h>
     24 #include <errno.h>
     25 #include <linux/sockios.h>
     26 #include <net/if.h>
     27 #include <netinet/in.h>
     28 #include <poll.h>
     29 #include <string.h>
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 #include <unistd.h>
     33 
     34 #include <cutils/properties.h>
     35 
     36 static const int kMaxDnsServers = 4;
     37 
     38 DhcpServer::DhcpServer(in_addr_t dhcpRangeStart,
     39                        in_addr_t dhcpRangeEnd,
     40                        in_addr_t netmask,
     41                        in_addr_t gateway,
     42                        unsigned int excludeInterface) :
     43     mNextAddressOffset(0),
     44     mDhcpRangeStart(dhcpRangeStart),
     45     mDhcpRangeEnd(dhcpRangeEnd),
     46     mNetmask(netmask),
     47     mGateway(gateway),
     48     mExcludeInterface(excludeInterface)
     49 {
     50 }
     51 
     52 Result DhcpServer::init() {
     53     Result res = mSocket.open(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     54     if (!res) {
     55         return res;
     56     }
     57     res = mSocket.enableOption(SOL_IP, IP_PKTINFO);
     58     if (!res) {
     59         return res;
     60     }
     61     res = mSocket.enableOption(SOL_SOCKET, SO_BROADCAST);
     62     if (!res) {
     63         return res;
     64     }
     65 
     66     res = mSocket.bindIp(INADDR_ANY, PORT_BOOTP_SERVER);
     67     if (!res) {
     68         return res;
     69     }
     70 
     71     return Result::success();
     72 }
     73 
     74 Result DhcpServer::run() {
     75     // Block all signals while we're running. This way we don't have to deal
     76     // with things like EINTR. We then uses ppoll to set the original mask while
     77     // polling. This way polling can be interrupted but socket writing, reading
     78     // and ioctl remain interrupt free. If a signal arrives while we're blocking
     79     // it it will be placed in the signal queue and handled once ppoll sets the
     80     // original mask. This way no signals are lost.
     81     sigset_t blockMask, originalMask;
     82     int status = ::sigfillset(&blockMask);
     83     if (status != 0) {
     84         return Result::error("Unable to fill signal set: %s", strerror(errno));
     85     }
     86     status = ::sigprocmask(SIG_SETMASK, &blockMask, &originalMask);
     87     if (status != 0) {
     88         return Result::error("Unable to set signal mask: %s", strerror(errno));
     89     }
     90 
     91     struct pollfd fds;
     92     fds.fd = mSocket.get();
     93     fds.events = POLLIN;
     94     Message message;
     95     while ((status = ::ppoll(&fds, 1, nullptr, &originalMask)) >= 0) {
     96         if (status == 0) {
     97             // Timeout
     98             continue;
     99         }
    100 
    101         unsigned int interfaceIndex = 0;
    102         Result res = mSocket.receiveFromInterface(&message,
    103                                                   &interfaceIndex);
    104         if (!res) {
    105             ALOGE("Failed to recieve on socket: %s", res.c_str());
    106             continue;
    107         }
    108         if (interfaceIndex == 0 || mExcludeInterface == interfaceIndex) {
    109             // Received packet on unknown or unwanted interface, drop it
    110             continue;
    111         }
    112         if (!message.isValidDhcpMessage(OP_BOOTREQUEST)) {
    113             // Not a DHCP request, drop it
    114             continue;
    115         }
    116         switch (message.type()) {
    117             case DHCPDISCOVER:
    118                 // Someone is trying to find us, let them know we exist
    119                 sendDhcpOffer(message, interfaceIndex);
    120                 break;
    121             case DHCPREQUEST:
    122                 // Someone wants a lease based on an offer
    123                 if (isValidDhcpRequest(message, interfaceIndex)) {
    124                     // The request matches our offer, acknowledge it
    125                     sendAck(message, interfaceIndex);
    126                 } else {
    127                     // Request for something other than we offered, denied
    128                     sendNack(message, interfaceIndex);
    129                 }
    130                 break;
    131         }
    132     }
    133     // Polling failed, exit
    134     return Result::error("Polling failed: %s", strerror(errno));
    135 }
    136 
    137 Result DhcpServer::sendMessage(unsigned int interfaceIndex,
    138                                in_addr_t /*sourceAddress*/,
    139                                const Message& message) {
    140     return mSocket.sendOnInterface(interfaceIndex,
    141                                    INADDR_BROADCAST,
    142                                    PORT_BOOTP_CLIENT,
    143                                    message);
    144 }
    145 
    146 void DhcpServer::sendDhcpOffer(const Message& message,
    147                                unsigned int interfaceIndex ) {
    148     updateDnsServers();
    149     in_addr_t offerAddress;
    150     Result res = getOfferAddress(interfaceIndex,
    151                                  message.dhcpData.chaddr,
    152                                  &offerAddress);
    153     if (!res) {
    154         ALOGE("Failed to get address for offer: %s", res.c_str());
    155         return;
    156     }
    157     in_addr_t serverAddress;
    158     res = getInterfaceAddress(interfaceIndex, &serverAddress);
    159     if (!res) {
    160         ALOGE("Failed to get address for interface %u: %s",
    161               interfaceIndex, res.c_str());
    162         return;
    163     }
    164 
    165     Message offer = Message::offer(message,
    166                                    serverAddress,
    167                                    offerAddress,
    168                                    mNetmask,
    169                                    mGateway,
    170                                    mDnsServers.data(),
    171                                    mDnsServers.size());
    172     res = sendMessage(interfaceIndex, serverAddress, offer);
    173     if (!res) {
    174         ALOGE("Failed to send DHCP offer: %s", res.c_str());
    175     }
    176 }
    177 
    178 void DhcpServer::sendAck(const Message& message, unsigned int interfaceIndex) {
    179     updateDnsServers();
    180     in_addr_t offerAddress, serverAddress;
    181     Result res = getOfferAddress(interfaceIndex,
    182                                  message.dhcpData.chaddr,
    183                                  &offerAddress);
    184     if (!res) {
    185         ALOGE("Failed to get address for offer: %s", res.c_str());
    186         return;
    187     }
    188     res = getInterfaceAddress(interfaceIndex, &serverAddress);
    189     if (!res) {
    190         ALOGE("Failed to get address for interface %u: %s",
    191               interfaceIndex, res.c_str());
    192         return;
    193     }
    194     Message ack = Message::ack(message,
    195                                serverAddress,
    196                                offerAddress,
    197                                mNetmask,
    198                                mGateway,
    199                                mDnsServers.data(),
    200                                mDnsServers.size());
    201     res = sendMessage(interfaceIndex, serverAddress, ack);
    202     if (!res) {
    203         ALOGE("Failed to send DHCP ack: %s", res.c_str());
    204     }
    205 }
    206 
    207 void DhcpServer::sendNack(const Message& message, unsigned int interfaceIndex) {
    208     in_addr_t serverAddress;
    209     Result res = getInterfaceAddress(interfaceIndex, &serverAddress);
    210     if (!res) {
    211         ALOGE("Failed to get address for interface %u: %s",
    212               interfaceIndex, res.c_str());
    213         return;
    214     }
    215     Message nack = Message::nack(message, serverAddress);
    216     res = sendMessage(interfaceIndex, serverAddress, nack);
    217     if (!res) {
    218         ALOGE("Failed to send DHCP nack: %s", res.c_str());
    219     }
    220 }
    221 
    222 bool DhcpServer::isValidDhcpRequest(const Message& message,
    223                                     unsigned int interfaceIndex) {
    224     in_addr_t offerAddress;
    225     Result res = getOfferAddress(interfaceIndex,
    226                                  message.dhcpData.chaddr,
    227                                  &offerAddress);
    228     if (!res) {
    229         ALOGE("Failed to get address for offer: %s", res.c_str());
    230         return false;
    231     }
    232     if (message.requestedIp() != offerAddress) {
    233         ALOGE("Client requested a different IP address from the offered one");
    234         return false;
    235     }
    236     return true;
    237 }
    238 
    239 void DhcpServer::updateDnsServers() {
    240     char key[64];
    241     char value[PROPERTY_VALUE_MAX];
    242     mDnsServers.clear();
    243     for (int i = 1; i <= kMaxDnsServers; ++i) {
    244         snprintf(key, sizeof(key), "net.eth0.dns%d", i);
    245         if (property_get(key, value, nullptr) > 0) {
    246             struct in_addr address;
    247             if (::inet_pton(AF_INET, value, &address) > 0) {
    248                 mDnsServers.push_back(address.s_addr);
    249             }
    250         }
    251     }
    252 }
    253 
    254 Result DhcpServer::getInterfaceAddress(unsigned int interfaceIndex,
    255                                        in_addr_t* address) {
    256     char interfaceName[IF_NAMESIZE + 1];
    257     if (if_indextoname(interfaceIndex, interfaceName) == nullptr) {
    258         return Result::error("Failed to get interface name for index %u: %s",
    259                              interfaceIndex, strerror(errno));
    260     }
    261     struct ifreq request;
    262     memset(&request, 0, sizeof(request));
    263     request.ifr_addr.sa_family = AF_INET;
    264     strncpy(request.ifr_name, interfaceName, IFNAMSIZ - 1);
    265 
    266     if (::ioctl(mSocket.get(), SIOCGIFADDR, &request) == -1) {
    267         return Result::error("Failed to get address for interface %s: %s",
    268                              interfaceName, strerror(errno));
    269     }
    270 
    271     auto inAddr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr);
    272     *address = inAddr->sin_addr.s_addr;
    273 
    274     return Result::success();
    275 }
    276 
    277 Result DhcpServer::getOfferAddress(unsigned int interfaceIndex,
    278                                    const uint8_t* macAddress,
    279                                    in_addr_t* address) {
    280     Lease key(interfaceIndex, macAddress);
    281 
    282     // Find or create entry, if it's created it will be zero and we update it
    283     in_addr_t& value = mLeases[key];
    284     if (value == 0) {
    285         // Addresses are stored in network byte order so when doing math on them
    286         // they have to be converted to host byte order
    287         in_addr_t nextAddress = ntohl(mDhcpRangeStart) + mNextAddressOffset;
    288         uint8_t lastAddressByte = nextAddress & 0xFF;
    289         while (lastAddressByte == 0xFF || lastAddressByte == 0) {
    290             // The address ends in .255 or .0 which means it's a broadcast or
    291             // network address respectively. Increase it further to avoid this.
    292             ++nextAddress;
    293             ++mNextAddressOffset;
    294         }
    295         if (nextAddress <= ntohl(mDhcpRangeEnd)) {
    296             // And then converted back again
    297             value = htonl(nextAddress);
    298             ++mNextAddressOffset;
    299         } else {
    300             // Ran out of addresses
    301             return Result::error("DHCP server is out of addresses");
    302         }
    303     }
    304     *address = value;
    305     return Result::success();
    306 }
    307 
    308