summaryrefslogtreecommitdiffstats
path: root/dhcp
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp')
-rw-r--r--dhcp/server/dhcpserver.cpp161
-rw-r--r--dhcp/server/dhcpserver.h26
-rw-r--r--dhcp/server/log.h2
-rw-r--r--dhcp/server/main.cpp87
4 files changed, 137 insertions, 139 deletions
diff --git a/dhcp/server/dhcpserver.cpp b/dhcp/server/dhcpserver.cpp
index 33fb61ad..d6d4a7ba 100644
--- a/dhcp/server/dhcpserver.cpp
+++ b/dhcp/server/dhcpserver.cpp
@@ -35,16 +35,7 @@
static const int kMaxDnsServers = 4;
-DhcpServer::DhcpServer(in_addr_t dhcpRangeStart,
- in_addr_t dhcpRangeEnd,
- in_addr_t netmask,
- in_addr_t gateway,
- unsigned int excludeInterface) :
- mNextAddressOffset(0),
- mDhcpRangeStart(dhcpRangeStart),
- mDhcpRangeEnd(dhcpRangeEnd),
- mNetmask(netmask),
- mGateway(gateway),
+DhcpServer::DhcpServer(unsigned int excludeInterface) :
mExcludeInterface(excludeInterface)
{
}
@@ -147,9 +138,13 @@ void DhcpServer::sendDhcpOffer(const Message& message,
unsigned int interfaceIndex ) {
updateDnsServers();
in_addr_t offerAddress;
+ in_addr_t netmask;
+ in_addr_t gateway;
Result res = getOfferAddress(interfaceIndex,
message.dhcpData.chaddr,
- &offerAddress);
+ &offerAddress,
+ &netmask,
+ &gateway);
if (!res) {
ALOGE("Failed to get address for offer: %s", res.c_str());
return;
@@ -165,8 +160,8 @@ void DhcpServer::sendDhcpOffer(const Message& message,
Message offer = Message::offer(message,
serverAddress,
offerAddress,
- mNetmask,
- mGateway,
+ netmask,
+ gateway,
mDnsServers.data(),
mDnsServers.size());
res = sendMessage(interfaceIndex, serverAddress, offer);
@@ -177,10 +172,15 @@ void DhcpServer::sendDhcpOffer(const Message& message,
void DhcpServer::sendAck(const Message& message, unsigned int interfaceIndex) {
updateDnsServers();
- in_addr_t offerAddress, serverAddress;
+ in_addr_t offerAddress;
+ in_addr_t netmask;
+ in_addr_t gateway;
+ in_addr_t serverAddress;
Result res = getOfferAddress(interfaceIndex,
message.dhcpData.chaddr,
- &offerAddress);
+ &offerAddress,
+ &netmask,
+ &gateway);
if (!res) {
ALOGE("Failed to get address for offer: %s", res.c_str());
return;
@@ -194,8 +194,8 @@ void DhcpServer::sendAck(const Message& message, unsigned int interfaceIndex) {
Message ack = Message::ack(message,
serverAddress,
offerAddress,
- mNetmask,
- mGateway,
+ netmask,
+ gateway,
mDnsServers.data(),
mDnsServers.size());
res = sendMessage(interfaceIndex, serverAddress, ack);
@@ -222,9 +222,13 @@ void DhcpServer::sendNack(const Message& message, unsigned int interfaceIndex) {
bool DhcpServer::isValidDhcpRequest(const Message& message,
unsigned int interfaceIndex) {
in_addr_t offerAddress;
+ in_addr_t netmask;
+ in_addr_t gateway;
Result res = getOfferAddress(interfaceIndex,
message.dhcpData.chaddr,
- &offerAddress);
+ &offerAddress,
+ &netmask,
+ &gateway);
if (!res) {
ALOGE("Failed to get address for offer: %s", res.c_str());
return false;
@@ -251,32 +255,99 @@ void DhcpServer::updateDnsServers() {
}
}
-Result DhcpServer::getInterfaceAddress(unsigned int interfaceIndex,
- in_addr_t* address) {
+Result DhcpServer::getInterfaceData(unsigned int interfaceIndex,
+ unsigned long type,
+ struct ifreq* response) {
char interfaceName[IF_NAMESIZE + 1];
if (if_indextoname(interfaceIndex, interfaceName) == nullptr) {
return Result::error("Failed to get interface name for index %u: %s",
interfaceIndex, strerror(errno));
}
- struct ifreq request;
- memset(&request, 0, sizeof(request));
- request.ifr_addr.sa_family = AF_INET;
- strncpy(request.ifr_name, interfaceName, IFNAMSIZ - 1);
+ memset(response, 0, sizeof(*response));
+ response->ifr_addr.sa_family = AF_INET;
+ strncpy(response->ifr_name, interfaceName, IFNAMSIZ - 1);
- if (::ioctl(mSocket.get(), SIOCGIFADDR, &request) == -1) {
- return Result::error("Failed to get address for interface %s: %s",
+ if (::ioctl(mSocket.get(), type, response) == -1) {
+ return Result::error("Failed to get data for interface %s: %s",
interfaceName, strerror(errno));
}
- auto inAddr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr);
- *address = inAddr->sin_addr.s_addr;
-
return Result::success();
}
+Result DhcpServer::getInterfaceAddress(unsigned int interfaceIndex,
+ in_addr_t* address) {
+ struct ifreq data;
+ Result res = getInterfaceData(interfaceIndex, SIOCGIFADDR, &data);
+ if (res.isSuccess()) {
+ auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr);
+ *address = inAddr->sin_addr.s_addr;
+ }
+ return res;
+}
+
+Result DhcpServer::getInterfaceNetmask(unsigned int interfaceIndex,
+ in_addr_t* address) {
+ struct ifreq data;
+ Result res = getInterfaceData(interfaceIndex, SIOCGIFNETMASK, &data);
+ if (res.isSuccess()) {
+ auto inAddr = reinterpret_cast<struct sockaddr_in*>(&data.ifr_addr);
+ *address = inAddr->sin_addr.s_addr;
+ }
+ return res;
+}
+
+static bool isValidHost(const in_addr_t address,
+ const in_addr_t interfaceAddress,
+ const in_addr_t netmask) {
+ // If the bits outside of the netmask are all zero it's a network address,
+ // don't use this.
+ bool isNetworkAddress = (address & ~netmask) == 0;
+ // If all bits outside of the netmask are set then it's a broadcast address,
+ // don't use this either.
+ bool isBroadcastAddress = (address & ~netmask) == ~netmask;
+ // Don't assign the interface address to a host
+ bool isInterfaceAddress = address == interfaceAddress;
+
+ return !isNetworkAddress && !isBroadcastAddress && !isInterfaceAddress;
+}
+
+static bool addressInRange(const in_addr_t address,
+ const in_addr_t interfaceAddress,
+ const in_addr_t netmask) {
+ if (address <= (interfaceAddress & netmask)) {
+ return false;
+ }
+ if (address >= (interfaceAddress | ~netmask)) {
+ return false;
+ }
+ return true;
+}
+
Result DhcpServer::getOfferAddress(unsigned int interfaceIndex,
const uint8_t* macAddress,
- in_addr_t* address) {
+ in_addr_t* address,
+ in_addr_t* netmask,
+ in_addr_t* gateway) {
+ // The interface address will be the gateway and will be used to determine
+ // the range of valid addresses (along with the netmask) for the client.
+ in_addr_t interfaceAddress = 0;
+ Result res = getInterfaceAddress(interfaceIndex, &interfaceAddress);
+ if (!res) {
+ return res;
+ }
+ // The netmask of the interface will be the netmask for the client as well
+ // as used to determine network range.
+ in_addr_t mask = 0;
+ res = getInterfaceNetmask(interfaceIndex, &mask);
+ if (!res) {
+ return res;
+ }
+
+ // Assign these values now before they are modified below
+ *gateway = interfaceAddress;
+ *netmask = mask;
+
Lease key(interfaceIndex, macAddress);
// Find or create entry, if it's created it will be zero and we update it
@@ -284,18 +355,30 @@ Result DhcpServer::getOfferAddress(unsigned int interfaceIndex,
if (value == 0) {
// Addresses are stored in network byte order so when doing math on them
// they have to be converted to host byte order
- in_addr_t nextAddress = ntohl(mDhcpRangeStart) + mNextAddressOffset;
- uint8_t lastAddressByte = nextAddress & 0xFF;
- while (lastAddressByte == 0xFF || lastAddressByte == 0) {
- // The address ends in .255 or .0 which means it's a broadcast or
- // network address respectively. Increase it further to avoid this.
+ interfaceAddress = ntohl(interfaceAddress);
+ mask = ntohl(mask);
+ // Get a reference to the offset so we can use it and increase it at the
+ // same time. If the entry does not exist it will be created with a
+ // value of zero.
+ in_addr_t& offset = mNextAddressOffsets[interfaceIndex];
+ if (offset == 0) {
+ // Increase if zero to avoid assigning network address
+ ++offset;
+ }
+ // Start out at the first address in the range as determined by netmask
+ in_addr_t nextAddress = (interfaceAddress & mask) + offset;
+
+ // Ensure the address is valid
+ while (!isValidHost(nextAddress, interfaceAddress, mask) &&
+ addressInRange(nextAddress, interfaceAddress, mask)) {
++nextAddress;
- ++mNextAddressOffset;
+ ++offset;
}
- if (nextAddress <= ntohl(mDhcpRangeEnd)) {
- // And then converted back again
+
+ if (addressInRange(nextAddress, interfaceAddress, mask)) {
+ // Convert back to network byte order
value = htonl(nextAddress);
- ++mNextAddressOffset;
+ ++offset;
} else {
// Ran out of addresses
return Result::error("DHCP server is out of addresses");
diff --git a/dhcp/server/dhcpserver.h b/dhcp/server/dhcpserver.h
index c5e1007d..276cd5b1 100644
--- a/dhcp/server/dhcpserver.h
+++ b/dhcp/server/dhcpserver.h
@@ -30,14 +30,9 @@ class Message;
class DhcpServer {
public:
- // Construct a DHCP server with the given parameters. Ignore any requests
- // and discoveries coming on the network interface identified by
- // |excludeInterface|.
- DhcpServer(in_addr_t dhcpRangeStart,
- in_addr_t dhcpRangeEnd,
- in_addr_t netmask,
- in_addr_t gateway,
- unsigned int excludeInterface);
+ // Construct a DHCP server. Ignore any requests and discoveries coming on
+ // the network interface identified by |excludeInterface|.
+ explicit DhcpServer(unsigned int excludeInterface);
Result init();
Result run();
@@ -54,24 +49,27 @@ private:
bool isValidDhcpRequest(const Message& message,
unsigned int interfaceIndex);
void updateDnsServers();
+ Result getInterfaceData(unsigned int interfaceIndex,
+ unsigned long type,
+ struct ifreq* response);
Result getInterfaceAddress(unsigned int interfaceIndex,
in_addr_t* address);
+ Result getInterfaceNetmask(unsigned int interfaceIndex,
+ in_addr_t* netmask);
Result getOfferAddress(unsigned int interfaceIndex,
const uint8_t* macAddress,
- in_addr_t* address);
+ in_addr_t* address,
+ in_addr_t* netmask,
+ in_addr_t* gateway);
Socket mSocket;
// This is the next address offset. This will be added to whatever the base
// address of the DHCP address range is. For each new MAC address seen this
// value will increase by one.
- in_addr_t mNextAddressOffset;
- in_addr_t mDhcpRangeStart;
- in_addr_t mDhcpRangeEnd;
- in_addr_t mNetmask;
- in_addr_t mGateway;
std::vector<in_addr_t> mDnsServers;
// Map a lease to an IP address for that lease
std::unordered_map<Lease, in_addr_t> mLeases;
+ std::unordered_map<unsigned int, in_addr_t> mNextAddressOffsets;
unsigned int mExcludeInterface;
};
diff --git a/dhcp/server/log.h b/dhcp/server/log.h
index bb1094fb..a0f21e08 100644
--- a/dhcp/server/log.h
+++ b/dhcp/server/log.h
@@ -16,5 +16,5 @@
#pragma once
#define LOG_TAG "dhcpserver"
-#include <cutils/log.h>
+#include <log/log.h>
diff --git a/dhcp/server/main.cpp b/dhcp/server/main.cpp
index eecafc1e..482ffd61 100644
--- a/dhcp/server/main.cpp
+++ b/dhcp/server/main.cpp
@@ -26,73 +26,10 @@ static void usage(const char* program) {
}
int main(int argc, char* argv[]) {
- in_addr_t rangeStart = 0;
- in_addr_t rangeEnd = 0;
- in_addr_t gateway = 0;
- in_addr_t netmask = 0;
char* excludeInterfaceName = nullptr;
unsigned int excludeInterfaceIndex = 0;
for (int i = 1; i < argc; ++i) {
- if (strcmp("--range", argv[i]) == 0) {
- if (i + 1 >= argc) {
- ALOGE("ERROR: Missing argument to --range parameter");
- usage(argv[0]);
- return 1;
- }
- char* divider = strchr(argv[i + 1], ',');
- if (divider != nullptr) {
- *divider = '\0';
- struct in_addr address;
- if (inet_pton(AF_INET, argv[i + 1], &address) > 0) {
- rangeStart = address.s_addr;
- } else {
- ALOGE("ERROR: Invalid start address '%s'", argv[i + 1]);
- usage(argv[0]);
- return 1;
- }
- char* next = divider + 1;
- if (inet_pton(AF_INET, next, &address) > 0) {
- rangeEnd = address.s_addr;
- } else {
- ALOGE("ERROR: Invalid end address '%s'", next);
- usage(argv[0]);
- return 1;
- }
- } else {
- ALOGE("ERROR: Invalid --range parameter '%s'", argv[i + 1]);
- usage(argv[0]);
- return 1;
- }
- ++i;
- } else if (strcmp("--gateway", argv[i]) == 0) {
- if (i + 1 >= argc) {
- ALOGE("ERROR: Missing argument to --gateway parameter");
- usage(argv[0]);
- return 1;
- }
- struct in_addr address;
- if (inet_pton(AF_INET, argv[i + 1], &address) > 0) {
- gateway = address.s_addr;
- } else {
- ALOGE("ERROR: Invalid gateway '%s'", argv[i + 1]);
- usage(argv[0]);
- return 1;
- }
- } else if (strcmp("--netmask", argv[i]) == 0) {
- if (i + 1 >= argc) {
- ALOGE("ERROR: Missing argument to --netmask parameter");
- usage(argv[0]);
- return 1;
- }
- struct in_addr address;
- if (inet_pton(AF_INET, argv[i + 1], &address) > 0) {
- netmask = address.s_addr;
- } else {
- ALOGE("ERROR: Invalid netmask '%s'", argv[i + 1]);
- usage(argv[0]);
- return 1;
- }
- } else if (strcmp("--exclude-interface", argv[i]) == 0) {
+ if (strcmp("--exclude-interface", argv[i]) == 0) {
if (i + 1 >= argc) {
ALOGE("ERROR: Missing argument to "
"--exclude-interfaces parameter");
@@ -110,27 +47,7 @@ int main(int argc, char* argv[]) {
}
}
- if (rangeStart == 0 || rangeEnd == 0) {
- ALOGE("ERROR: Missing or invalid --range argument");
- usage(argv[0]);
- return 1;
- }
- if (gateway == 0) {
- ALOGE("ERROR: Missing or invalid --gateway argument");
- usage(argv[0]);
- return 1;
- }
- if (netmask == 0) {
- ALOGE("ERROR: Missing or invalid --netmask argument");
- usage(argv[0]);
- return 1;
- }
-
- DhcpServer server(rangeStart,
- rangeEnd,
- netmask,
- gateway,
- excludeInterfaceIndex);
+ DhcpServer server(excludeInterfaceIndex);
Result res = server.init();
if (!res) {
ALOGE("Failed to initialize DHCP server: %s\n", res.c_str());