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