summaryrefslogtreecommitdiffhomepage
path: root/src/dhcpv4.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2017-07-03 16:39:21 +0200
committerHans Dedecker <dedeckeh@gmail.com>2017-08-07 15:27:20 +0200
commit95d0fb6c25944985b9717a51cebaa7ea8dc7222d (patch)
tree511a3d34366f148043a1920bf54b414ed7962199 /src/dhcpv4.c
parent296b4a0ddd7d6d77e48ee36f3407b0769caaa0d7 (diff)
treewide: rework IPv4 address logic
Align IPv4 address logic with IPv6 by caching per interface the assigned IPv4 addresses. This allows to get rid of different ioctl calls in the DHCPv4 logic to retrieve the IPv4 address and netmask in use by an interface. Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'src/dhcpv4.c')
-rw-r--r--src/dhcpv4.c88
1 files changed, 37 insertions, 51 deletions
diff --git a/src/dhcpv4.c b/src/dhcpv4.c
index e1f0df6..976e1c9 100644
--- a/src/dhcpv4.c
+++ b/src/dhcpv4.c
@@ -95,42 +95,36 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
return -1;
}
- /* Create a range if not specified */
- struct ifreq ifreq;
- strncpy(ifreq.ifr_name, iface->ifname, sizeof(ifreq.ifr_name));
+ uint32_t mask = iface->addr4[0].prefix ? htonl(~((1 << (32 - iface->addr4[0].prefix)) - 1)) : 0;
- struct sockaddr_in *saddr = (struct sockaddr_in*)&ifreq.ifr_addr;
- struct sockaddr_in *smask = (struct sockaddr_in*)&ifreq.ifr_netmask;
+ /* Create a range if not specified */
if (!(iface->dhcpv4_start.s_addr & htonl(0xffff0000)) &&
!(iface->dhcpv4_end.s_addr & htonl(0xffff0000)) &&
- !ioctl(sock, SIOCGIFADDR, &ifreq)) {
- struct in_addr addr = saddr->sin_addr;
-
- ioctl(sock, SIOCGIFNETMASK, &ifreq);
- struct in_addr mask = smask->sin_addr;
+ iface->addr4_len) {
+ struct in_addr *addr = &iface->addr4[0].addr.in;
uint32_t start = ntohl(iface->dhcpv4_start.s_addr);
uint32_t end = ntohl(iface->dhcpv4_end.s_addr);
if (start && end && start < end &&
- start > ntohl(addr.s_addr & ~mask.s_addr) &&
- (start & ntohl(~mask.s_addr)) == start &&
- (end & ntohl(~mask.s_addr)) == end) {
+ start > ntohl(addr->s_addr & ~mask) &&
+ (start & ntohl(~mask)) == start &&
+ (end & ntohl(~mask)) == end) {
iface->dhcpv4_start.s_addr = htonl(start) |
- (addr.s_addr & mask.s_addr);
+ (addr->s_addr & mask);
iface->dhcpv4_end.s_addr = htonl(end) |
- (addr.s_addr & mask.s_addr);
- } else if (ntohl(mask.s_addr) <= 0xfffffff0) {
- start = addr.s_addr & mask.s_addr;
- end = addr.s_addr & mask.s_addr;
+ (addr->s_addr & mask);
+ } else if (ntohl(mask) <= 0xfffffff0) {
+ start = addr->s_addr & mask;
+ end = addr->s_addr & mask;
- if (ntohl(mask.s_addr) <= 0xffffff00) {
+ if (ntohl(mask) <= 0xffffff00) {
iface->dhcpv4_start.s_addr = start | htonl(100);
iface->dhcpv4_end.s_addr = end | htonl(250);
- } else if (ntohl(mask.s_addr) <= 0xffffffc0) {
+ } else if (ntohl(mask) <= 0xffffffc0) {
iface->dhcpv4_start.s_addr = start | htonl(10);
iface->dhcpv4_end.s_addr = end | htonl(60);
- } else if (ntohl(mask.s_addr) <= 0xffffffe0) {
+ } else if (ntohl(mask) <= 0xffffffe0) {
iface->dhcpv4_start.s_addr = start | htonl(10);
iface->dhcpv4_end.s_addr = end | htonl(30);
} else {
@@ -186,8 +180,8 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable)
// Clean invalid assignments
struct dhcpv4_assignment *a, *n;
list_for_each_entry_safe(a, n, &iface->dhcpv4_assignments, head) {
- if ((htonl(a->addr) & smask->sin_addr.s_addr) !=
- (iface->dhcpv4_start.s_addr & smask->sin_addr.s_addr))
+ if ((htonl(a->addr) & mask) !=
+ (iface->dhcpv4_start.s_addr & mask))
free_dhcpv4_assignment(a);
}
@@ -261,35 +255,26 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
req->op != DHCPV4_BOOTREQUEST || req->hlen != 6)
return;
- int sock = iface->dhcpv4_event.uloop.fd;
- struct sockaddr_in ifaddr;
- struct sockaddr_in ifnetmask;
syslog(LOG_NOTICE, "Got DHCPv4 request");
- struct ifreq ifreq;
- memcpy(ifreq.ifr_name, iface->ifname, sizeof(ifreq.ifr_name));
- if (ioctl(sock, SIOCGIFADDR, &ifreq)) {
- syslog(LOG_WARNING, "DHCPv4 failed to detect address: %s", strerror(errno));
+ if (!iface->addr4_len) {
+ syslog(LOG_WARNING, "DHCPv4 no address found on %s", iface->name);
return;
}
- memcpy(&ifaddr, &ifreq.ifr_addr, sizeof(ifaddr));
- if (ioctl(sock, SIOCGIFNETMASK, &ifreq))
- return;
-
- memcpy(&ifnetmask, &ifreq.ifr_netmask, sizeof(ifnetmask));
- uint32_t network = ifaddr.sin_addr.s_addr & ifnetmask.sin_addr.s_addr;
+ struct in_addr *ifaddr = &iface->addr4[0].addr.in;
+ struct in_addr *ifbroadcast = &iface->addr4[0].broadcast;
+ uint32_t mask = iface->addr4[0].prefix ? htonl(~((1 << (32 - iface->addr4[0].prefix)) - 1)) : 0;
+ uint32_t network = iface->addr4[0].addr.in.s_addr & mask;
+ int sock = iface->dhcpv4_event.uloop.fd;
- if ((iface->dhcpv4_start.s_addr & ifnetmask.sin_addr.s_addr) != network ||
- (iface->dhcpv4_end.s_addr & ifnetmask.sin_addr.s_addr) != network) {
+ if ((iface->dhcpv4_start.s_addr & mask) != network ||
+ (iface->dhcpv4_end.s_addr & mask) != network) {
syslog(LOG_WARNING, "DHCPv4 range out of assigned network");
return;
}
- struct ifreq ifr = {.ifr_name = ""};
- strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
-
struct dhcpv4_message reply = {
.op = DHCPV4_BOOTREPLY,
.htype = 1,
@@ -300,7 +285,7 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
.flags = req->flags,
.ciaddr = {INADDR_ANY},
.giaddr = req->giaddr,
- .siaddr = ifaddr.sin_addr,
+ .siaddr = *ifaddr,
};
memcpy(reply.chaddr, req->chaddr, sizeof(reply.chaddr));
@@ -331,7 +316,7 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
} else if (opt->type == DHCPV4_OPT_IPADDRESS && opt->len == 4)
memcpy(&reqaddr, opt->data, 4);
else if (opt->type == DHCPV4_OPT_SERVERID && opt->len == 4) {
- if (memcmp(opt->data, &ifaddr.sin_addr, 4))
+ if (memcmp(opt->data, ifaddr, 4))
return;
} else if (iface->filter_class && opt->type == DHCPV4_OPT_USER_CLASS) {
uint8_t *c = opt->data, *cend = &opt->data[opt->len];
@@ -385,7 +370,7 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
return;
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_MESSAGE, 1, &msg);
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_SERVERID, 4, &ifaddr.sin_addr);
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_SERVERID, 4, ifaddr);
if (lease) {
uint32_t val;
@@ -403,18 +388,19 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_REBIND, 4, &val);
}
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NETMASK, 4, &ifnetmask.sin_addr);
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_NETMASK, 4, &mask);
if (lease->hostname)
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_HOSTNAME,
strlen(lease->hostname), lease->hostname);
- if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) {
- struct sockaddr_in *ina = (struct sockaddr_in*)&ifr.ifr_broadaddr;
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_BROADCAST, 4, &ina->sin_addr);
- }
+ if (ifbroadcast->s_addr != INADDR_ANY)
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_BROADCAST, 4, ifbroadcast);
}
+ struct ifreq ifr = {.ifr_name = ""};
+ strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
+
if (!ioctl(sock, SIOCGIFMTU, &ifr)) {
uint16_t mtu = htons(ifr.ifr_mtu);
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_MTU, 2, &mtu);
@@ -433,14 +419,14 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
}
if (iface->dhcpv4_router_cnt == 0)
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 4, &ifaddr.sin_addr);
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 4, ifaddr);
else
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER,
4 * iface->dhcpv4_router_cnt, iface->dhcpv4_router);
if (iface->dhcpv4_dns_cnt == 0)
- dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 4, &ifaddr.sin_addr);
+ dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER, 4, ifaddr);
else
dhcpv4_put(&reply, &cookie, DHCPV4_OPT_DNSSERVER,
4 * iface->dhcpv4_dns_cnt, iface->dhcpv4_dns);