• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DhcpServer(unsigned int excludeInterface)38 DhcpServer::DhcpServer(unsigned int excludeInterface) :
39     mExcludeInterface(excludeInterface)
40 {
41 }
42 
init()43 Result DhcpServer::init() {
44     Result res = mSocket.open(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
45     if (!res) {
46         return res;
47     }
48     res = mSocket.enableOption(SOL_IP, IP_PKTINFO);
49     if (!res) {
50         return res;
51     }
52     res = mSocket.enableOption(SOL_SOCKET, SO_BROADCAST);
53     if (!res) {
54         return res;
55     }
56 
57     res = mSocket.bindIp(INADDR_ANY, PORT_BOOTP_SERVER);
58     if (!res) {
59         return res;
60     }
61 
62     return Result::success();
63 }
64 
run()65 Result DhcpServer::run() {
66     // Block all signals while we're running. This way we don't have to deal
67     // with things like EINTR. We then uses ppoll to set the original mask while
68     // polling. This way polling can be interrupted but socket writing, reading
69     // and ioctl remain interrupt free. If a signal arrives while we're blocking
70     // it it will be placed in the signal queue and handled once ppoll sets the
71     // original mask. This way no signals are lost.
72     sigset_t blockMask, originalMask;
73     int status = ::sigfillset(&blockMask);
74     if (status != 0) {
75         return Result::error("Unable to fill signal set: %s", strerror(errno));
76     }
77     status = ::sigprocmask(SIG_SETMASK, &blockMask, &originalMask);
78     if (status != 0) {
79         return Result::error("Unable to set signal mask: %s", strerror(errno));
80     }
81 
82     struct pollfd fds;
83     fds.fd = mSocket.get();
84     fds.events = POLLIN;
85     Message message;
86     while ((status = ::ppoll(&fds, 1, nullptr, &originalMask)) >= 0) {
87         if (status == 0) {
88             // Timeout
89             continue;
90         }
91 
92         unsigned int interfaceIndex = 0;
93         Result res = mSocket.receiveFromInterface(&message,
94                                                   &interfaceIndex);
95         if (!res) {
96             ALOGE("Failed to recieve on socket: %s", res.c_str());
97             continue;
98         }
99         if (interfaceIndex == 0 || mExcludeInterface == interfaceIndex) {
100             // Received packet on unknown or unwanted interface, drop it
101             continue;
102         }
103         if (!message.isValidDhcpMessage(OP_BOOTREQUEST)) {
104             // Not a DHCP request, drop it
105             continue;
106         }
107         switch (message.type()) {
108             case DHCPDISCOVER:
109                 // Someone is trying to find us, let them know we exist
110                 sendDhcpOffer(message, interfaceIndex);
111                 break;
112             case DHCPREQUEST:
113                 // Someone wants a lease based on an offer
114                 if (isValidDhcpRequest(message, interfaceIndex)) {
115                     // The request matches our offer, acknowledge it
116                     sendAck(message, interfaceIndex);
117                 } else {
118                     // Request for something other than we offered, denied
119                     sendNack(message, interfaceIndex);
120                 }
121                 break;
122         }
123     }
124     // Polling failed, exit
125     return Result::error("Polling failed: %s", strerror(errno));
126 }
127 
sendMessage(unsigned int interfaceIndex,in_addr_t,const Message & message)128 Result DhcpServer::sendMessage(unsigned int interfaceIndex,
129                                in_addr_t /*sourceAddress*/,
130                                const Message& message) {
131     return mSocket.sendOnInterface(interfaceIndex,
132                                    INADDR_BROADCAST,
133                                    PORT_BOOTP_CLIENT,
134                                    message);
135 }
136 
sendDhcpOffer(const Message & message,unsigned int interfaceIndex)137 void DhcpServer::sendDhcpOffer(const Message& message,
138                                unsigned int interfaceIndex ) {
139     updateDnsServers();
140     in_addr_t offerAddress;
141     in_addr_t netmask;
142     in_addr_t gateway;
143     Result res = getOfferAddress(interfaceIndex,
144                                  message.dhcpData.chaddr,
145                                  &offerAddress,
146                                  &netmask,
147                                  &gateway);
148     if (!res) {
149         ALOGE("Failed to get address for offer: %s", res.c_str());
150         return;
151     }
152     in_addr_t serverAddress;
153     res = getInterfaceAddress(interfaceIndex, &serverAddress);
154     if (!res) {
155         ALOGE("Failed to get address for interface %u: %s",
156               interfaceIndex, res.c_str());
157         return;
158     }
159 
160     Message offer = Message::offer(message,
161                                    serverAddress,
162                                    offerAddress,
163                                    netmask,
164                                    gateway,
165                                    mDnsServers.data(),
166                                    mDnsServers.size());
167     res = sendMessage(interfaceIndex, serverAddress, offer);
168     if (!res) {
169         ALOGE("Failed to send DHCP offer: %s", res.c_str());
170     }
171 }
172 
sendAck(const Message & message,unsigned int interfaceIndex)173 void DhcpServer::sendAck(const Message& message, unsigned int interfaceIndex) {
174     updateDnsServers();
175     in_addr_t offerAddress;
176     in_addr_t netmask;
177     in_addr_t gateway;
178     in_addr_t serverAddress;
179     Result res = getOfferAddress(interfaceIndex,
180                                  message.dhcpData.chaddr,
181                                  &offerAddress,
182                                  &netmask,
183                                  &gateway);
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                                netmask,
198                                gateway,
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 
sendNack(const Message & message,unsigned int interfaceIndex)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 
isValidDhcpRequest(const Message & message,unsigned int interfaceIndex)222 bool DhcpServer::isValidDhcpRequest(const Message& message,
223                                     unsigned int interfaceIndex) {
224     in_addr_t offerAddress;
225     in_addr_t netmask;
226     in_addr_t gateway;
227     Result res = getOfferAddress(interfaceIndex,
228                                  message.dhcpData.chaddr,
229                                  &offerAddress,
230                                  &netmask,
231                                  &gateway);
232     if (!res) {
233         ALOGE("Failed to get address for offer: %s", res.c_str());
234         return false;
235     }
236     if (message.requestedIp() != offerAddress) {
237         ALOGE("Client requested a different IP address from the offered one");
238         return false;
239     }
240     return true;
241 }
242 
updateDnsServers()243 void DhcpServer::updateDnsServers() {
244     char key[64];
245     char value[PROPERTY_VALUE_MAX];
246     mDnsServers.clear();
247     for (int i = 1; i <= kMaxDnsServers; ++i) {
248         snprintf(key, sizeof(key), "net.eth0.dns%d", i);
249         if (property_get(key, value, nullptr) > 0) {
250             struct in_addr address;
251             if (::inet_pton(AF_INET, value, &address) > 0) {
252                 mDnsServers.push_back(address.s_addr);
253             }
254         }
255     }
256 }
257 
getInterfaceData(unsigned int interfaceIndex,unsigned long type,struct ifreq * response)258 Result DhcpServer::getInterfaceData(unsigned int interfaceIndex,
259                                     unsigned long type,
260                                     struct ifreq* response) {
261     char interfaceName[IF_NAMESIZE + 1];
262     if (if_indextoname(interfaceIndex, interfaceName) == nullptr) {
263         return Result::error("Failed to get interface name for index %u: %s",
264                              interfaceIndex, strerror(errno));
265     }
266     memset(response, 0, sizeof(*response));
267     response->ifr_addr.sa_family = AF_INET;
268     strncpy(response->ifr_name, interfaceName, IFNAMSIZ - 1);
269 
270     if (::ioctl(mSocket.get(), type, response) == -1) {
271         return Result::error("Failed to get data for interface %s: %s",
272                              interfaceName, strerror(errno));
273     }
274 
275     return Result::success();
276 }
277 
getInterfaceAddress(unsigned int interfaceIndex,in_addr_t * address)278 Result DhcpServer::getInterfaceAddress(unsigned int interfaceIndex,
279                                        in_addr_t* address) {
280     struct ifreq data;
281     Result res = getInterfaceData(interfaceIndex, SIOCGIFADDR, &data);
282     if (res.isSuccess()) {
283         auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr);
284         *address = inAddr->sin_addr.s_addr;
285     }
286     return res;
287 }
288 
getInterfaceNetmask(unsigned int interfaceIndex,in_addr_t * address)289 Result DhcpServer::getInterfaceNetmask(unsigned int interfaceIndex,
290                                        in_addr_t* address) {
291     struct ifreq data;
292     Result res = getInterfaceData(interfaceIndex, SIOCGIFNETMASK, &data);
293     if (res.isSuccess()) {
294         auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr);
295         *address = inAddr->sin_addr.s_addr;
296     }
297     return res;
298 }
299 
isValidHost(const in_addr_t address,const in_addr_t interfaceAddress,const in_addr_t netmask)300 static bool isValidHost(const in_addr_t address,
301                         const in_addr_t interfaceAddress,
302                         const in_addr_t netmask) {
303     // If the bits outside of the netmask are all zero it's a network address,
304     // don't use this.
305     bool isNetworkAddress = (address & ~netmask) == 0;
306     // If all bits outside of the netmask are set then it's a broadcast address,
307     // don't use this either.
308     bool isBroadcastAddress = (address & ~netmask) == ~netmask;
309     // Don't assign the interface address to a host
310     bool isInterfaceAddress = address == interfaceAddress;
311 
312     return !isNetworkAddress && !isBroadcastAddress && !isInterfaceAddress;
313 }
314 
addressInRange(const in_addr_t address,const in_addr_t interfaceAddress,const in_addr_t netmask)315 static bool addressInRange(const in_addr_t address,
316                            const in_addr_t interfaceAddress,
317                            const in_addr_t netmask) {
318     if (address <= (interfaceAddress & netmask)) {
319         return false;
320     }
321     if (address >= (interfaceAddress | ~netmask)) {
322         return false;
323     }
324     return true;
325 }
326 
getOfferAddress(unsigned int interfaceIndex,const uint8_t * macAddress,in_addr_t * address,in_addr_t * netmask,in_addr_t * gateway)327 Result DhcpServer::getOfferAddress(unsigned int interfaceIndex,
328                                    const uint8_t* macAddress,
329                                    in_addr_t* address,
330                                    in_addr_t* netmask,
331                                    in_addr_t* gateway) {
332     // The interface address will be the gateway and will be used to determine
333     // the range of valid addresses (along with the netmask) for the client.
334     in_addr_t interfaceAddress = 0;
335     Result res = getInterfaceAddress(interfaceIndex, &interfaceAddress);
336     if (!res) {
337         return res;
338     }
339     // The netmask of the interface will be the netmask for the client as well
340     // as used to determine network range.
341     in_addr_t mask = 0;
342     res = getInterfaceNetmask(interfaceIndex, &mask);
343     if (!res) {
344         return res;
345     }
346 
347     // Assign these values now before they are modified below
348     *gateway = interfaceAddress;
349     *netmask = mask;
350 
351     Lease key(interfaceIndex, macAddress);
352 
353     // Find or create entry, if it's created it will be zero and we update it
354     in_addr_t& value = mLeases[key];
355     if (value == 0) {
356         // Addresses are stored in network byte order so when doing math on them
357         // they have to be converted to host byte order
358         interfaceAddress = ntohl(interfaceAddress);
359         mask = ntohl(mask);
360         // Get a reference to the offset so we can use it and increase it at the
361         // same time. If the entry does not exist it will be created with a
362         // value of zero.
363         in_addr_t& offset = mNextAddressOffsets[interfaceIndex];
364         if (offset == 0) {
365             // Increase if zero to avoid assigning network address
366             ++offset;
367         }
368         // Start out at the first address in the range as determined by netmask
369         in_addr_t nextAddress = (interfaceAddress & mask) + offset;
370 
371         // Ensure the address is valid
372         while (!isValidHost(nextAddress, interfaceAddress, mask) &&
373                addressInRange(nextAddress, interfaceAddress, mask)) {
374             ++nextAddress;
375             ++offset;
376         }
377 
378         if (addressInRange(nextAddress, interfaceAddress, mask)) {
379             // Convert back to network byte order
380             value = htonl(nextAddress);
381             ++offset;
382         } else {
383             // Ran out of addresses
384             return Result::error("DHCP server is out of addresses");
385         }
386     }
387     *address = value;
388     return Result::success();
389 }
390 
391