summaryrefslogtreecommitdiffhomepage
path: root/src/odhcpd.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/odhcpd.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/odhcpd.c')
-rw-r--r--src/odhcpd.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/odhcpd.c b/src/odhcpd.c
index 6f38d5c..5b739d0 100644
--- a/src/odhcpd.c
+++ b/src/odhcpd.c
@@ -234,7 +234,7 @@ static int cb_valid_handler(struct nl_msg *msg, void *arg)
struct odhcpd_ipaddr *addrs = *(ctxt->addrs);
struct nlmsghdr *hdr = nlmsg_hdr(msg);
struct ifaddrmsg *ifa;
- struct nlattr *nla[__IFA_MAX];
+ struct nlattr *nla[__IFA_MAX], *nla_addr = NULL;
if (hdr->nlmsg_type != RTM_NEWADDR)
return NL_SKIP;
@@ -246,7 +246,22 @@ static int cb_valid_handler(struct nl_msg *msg, void *arg)
return NL_SKIP;
nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL);
- if (!nla[IFA_ADDRESS])
+
+ switch (ifa->ifa_family) {
+ case AF_INET6:
+ if (nla[IFA_ADDRESS])
+ nla_addr = nla[IFA_ADDRESS];
+ break;
+
+ case AF_INET:
+ if (nla[IFA_LOCAL])
+ nla_addr = nla[IFA_LOCAL];
+ break;
+
+ default:
+ break;
+ }
+ if (!nla_addr)
return NL_SKIP;
addrs = realloc(addrs, sizeof(*addrs)*(ctxt->ret + 1));
@@ -256,9 +271,13 @@ static int cb_valid_handler(struct nl_msg *msg, void *arg)
memset(&addrs[ctxt->ret], 0, sizeof(addrs[ctxt->ret]));
addrs[ctxt->ret].prefix = ifa->ifa_prefixlen;
- nla_memcpy(&addrs[ctxt->ret].addr, nla[IFA_ADDRESS],
+ nla_memcpy(&addrs[ctxt->ret].addr, nla_addr,
sizeof(addrs[ctxt->ret].addr));
+ if (nla[IFA_BROADCAST])
+ nla_memcpy(&addrs[ctxt->ret].broadcast, nla[IFA_BROADCAST],
+ sizeof(addrs[ctxt->ret].broadcast));
+
if (nla[IFA_CACHEINFO]) {
struct ifa_cacheinfo *ifc = nla_data(nla[IFA_CACHEINFO]);
@@ -295,8 +314,15 @@ static int cb_error_handler(_unused struct sockaddr_nl *nla, struct nlmsgerr *er
return NL_STOP;
}
-// compare prefixes
-static int prefixcmp(const void *va, const void *vb)
+static int prefix_cmp(const void *va, const void *vb)
+{
+ const struct odhcpd_ipaddr *a = va, *b = vb;
+ return (ntohl(a->addr.in.s_addr) < ntohl(b->addr.in.s_addr)) ? 1 :
+ (ntohl(a->addr.in.s_addr) > ntohl(b->addr.in.s_addr)) ? -1 : 0;
+}
+
+// compare IPv6 prefixes
+static int prefix6_cmp(const void *va, const void *vb)
{
const struct odhcpd_ipaddr *a = va, *b = vb;
uint32_t a_pref = IN6_IS_ADDR_ULA(&a->addr.in6) ? 1 : a->preferred;
@@ -353,7 +379,7 @@ ssize_t odhcpd_get_interface_addresses(int ifindex, bool v6, struct odhcpd_ipadd
time_t now = odhcpd_time();
struct odhcpd_ipaddr *addr = *addrs;
- qsort(addr, ctxt.ret, sizeof(*addr), prefixcmp);
+ qsort(addr, ctxt.ret, sizeof(*addr), v6 ? prefix6_cmp : prefix_cmp);
for (ssize_t i = 0; i < ctxt.ret; ++i) {
if (addr[i].preferred < UINT32_MAX - now)