+#include "socket-util.h"
+#include "resolved.h"
+
+#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
+
+static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+ Manager *m = userdata;
+ uint16_t type;
+ Link *l;
+ int ifindex, r;
+
+ assert(rtnl);
+ assert(m);
+ assert(mm);
+
+ r = sd_rtnl_message_get_type(mm, &type);
+ if (r < 0)
+ goto fail;
+
+ r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
+ if (r < 0)
+ goto fail;
+
+ l = hashmap_get(m->links, INT_TO_PTR(ifindex));
+
+ switch (type) {
+
+ case RTM_NEWLINK:
+ if (!l) {
+ log_debug("Found link %i", ifindex);
+
+ r = link_new(m, &l, ifindex);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = link_update_rtnl(l, mm);
+ if (r < 0)
+ goto fail;
+
+ break;
+
+ case RTM_DELLINK:
+ if (l) {
+ log_debug("Removing link %i", l->ifindex);
+ link_free(l);
+ }
+
+ break;
+ }
+
+ return 0;
+
+fail:
+ log_warning("Failed to process RTNL link message: %s", strerror(-r));
+ return 0;
+}
+
+static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userdata) {
+ Manager *m = userdata;
+ union in_addr_union address;
+ unsigned char family;
+ uint16_t type;
+ int r, ifindex;
+ LinkAddress *a;
+ Link *l;
+
+ assert(rtnl);
+ assert(mm);
+ assert(m);
+
+ r = sd_rtnl_message_get_type(mm, &type);
+ if (r < 0)
+ goto fail;
+
+ r = sd_rtnl_message_addr_get_ifindex(mm, &ifindex);
+ if (r < 0)
+ goto fail;
+
+ l = hashmap_get(m->links, INT_TO_PTR(ifindex));
+ if (!l)
+ return 0;
+
+ r = sd_rtnl_message_addr_get_family(mm, &family);
+ if (r < 0)
+ goto fail;
+
+ switch (family) {
+
+ case AF_INET:
+ r = sd_rtnl_message_read_in_addr(mm, IFA_LOCAL, &address.in);
+ if (r < 0) {
+ r = sd_rtnl_message_read_in_addr(mm, IFA_ADDRESS, &address.in);
+ if (r < 0)
+ goto fail;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_rtnl_message_read_in6_addr(mm, IFA_LOCAL, &address.in6);
+ if (r < 0) {
+ r = sd_rtnl_message_read_in6_addr(mm, IFA_ADDRESS, &address.in6);
+ if (r < 0)
+ goto fail;
+ }
+
+ break;
+
+ default:
+ return 0;
+ }
+
+ a = link_find_address(l, family, &address);
+
+ switch (type) {
+
+ case RTM_NEWADDR:
+
+ if (!a) {
+ r = link_address_new(l, &a, family, &address);
+ if (r < 0)
+ return r;
+ }
+
+ r = link_address_update_rtnl(a, mm);
+ if (r < 0)
+ return r;
+
+ break;
+
+ case RTM_DELADDR:
+ if (a)
+ link_address_free(a);
+ break;
+ }
+
+ return 0;
+
+fail:
+ log_warning("Failed to process RTNL address message: %s", strerror(-r));
+ return 0;
+}
+
+
+static int manager_rtnl_listen(Manager *m) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+ sd_rtnl_message *i;
+ int r;
+
+ assert(m);
+
+ /* First, subscibe to interfaces coming and going */
+ r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, manager_process_link, m);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, manager_process_link, m);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, manager_process_address, m);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, manager_process_address, m);
+ if (r < 0)
+ return r;