diff --git a/src/netlink.c b/src/netlink.c index 30bece27029941afb23c978d7519e234df7fbf01..b66be548f8302d8ec8621b02c0885cb6a6e88a35 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -408,6 +408,51 @@ static int hostmngr_handle_nlevents_link(struct hostmngr_private *priv, return NL_OK; } +static int hostmngr_handle_nlevents_addr(struct hostmngr_private *priv, + struct nlmsghdr *hdr) +{ + struct ifaddrmsg *ifa = nlmsg_data(hdr); + struct nlattr *nla[__IFA_MAX]; + struct local_interface *iface = NULL; + char ifname[IFNAMSIZ] = {0}; + struct ip_address ips[32] = {0}; + int num_ipaddrs = 32; + int ret; + + if (!nlmsg_valid_hdr(hdr, sizeof(*ifa)) || + (ifa->ifa_family != AF_INET6 && ifa->ifa_family != AF_INET)) + return NL_SKIP; + + nlmsg_parse(hdr, sizeof(*ifa), nla, __IFA_MAX - 1, NULL); + + if_indextoname(ifa->ifa_index, ifname); + iface = hostmngr_ifname_to_interface(priv, ifname); + if (!iface) + return NL_SKIP; + + ret = if_getaddrs(iface->ifname, ips, &num_ipaddrs); + if (ret) + return NL_SKIP; + + if (num_ipaddrs == iface->num_ipaddrs && + memcmp(iface->ipaddrs, ips, num_ipaddrs * sizeof(struct ip_address)) == 0) + return NL_OK; + + free(iface->ipaddrs); + iface->ipaddrs = NULL; + iface->num_ipaddrs = 0; + + if (num_ipaddrs > 0) { + iface->ipaddrs = calloc(num_ipaddrs, sizeof(struct ip_address)); + if (iface->ipaddrs) { + iface->num_ipaddrs = num_ipaddrs; + memcpy(iface->ipaddrs, ips, num_ipaddrs * sizeof(struct ip_address)); + } + } + + return NL_OK; +} + static int hostmngr_nlevents_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *hdr = nlmsg_hdr(msg); @@ -422,13 +467,11 @@ static int hostmngr_nlevents_cb(struct nl_msg *msg, void *arg) case RTM_DELLINK: ret = hostmngr_handle_nlevents_link(priv, hdr, add); break; -#if 0 //TODO: when needed case RTM_NEWADDR: - add = true; + /* falltrough */ case RTM_DELADDR: - ret = hostmngr_handle_nlevents_addr(priv, hdr, add); + ret = hostmngr_handle_nlevents_addr(priv, hdr); break; -#endif case RTM_NEWNEIGH: add = true; case RTM_DELNEIGH: @@ -493,6 +536,7 @@ int hostmngr_register_nlevents(struct hostmngr_private *priv) hostmngr_nlevents_cb, priv); if (nl_socket_add_memberships(rtnl_event.sock, + RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_NEIGH, RTNLGRP_LINK, 0)) goto out_err;