Try<vector<Info> > infos(int family, int states) { Try<Netlink<struct nl_sock> > sock = routing::socket(NETLINK_INET_DIAG); if (sock.isError()) { return Error(sock.error()); } struct nl_cache* c = NULL; int err = idiagnl_msg_alloc_cache(sock.get().get(), family, states, &c); if (err != 0) { return Error(nl_geterror(err)); } Netlink<struct nl_cache> cache(c); vector<Info> results; for (struct nl_object* o = nl_cache_get_first(cache.get()); o != NULL; o = nl_cache_get_next(o)) { struct idiagnl_msg* msg = (struct idiagnl_msg*)o; // For 'state', libnl-idiag only returns the number of left // shifts. Convert it back to power-of-2 number. results.push_back(Info( idiagnl_msg_get_family(msg), 1 << idiagnl_msg_get_state(msg), idiagnl_msg_get_sport(msg), idiagnl_msg_get_dport(msg), IP(idiagnl_msg_get_src(msg)), IP(idiagnl_msg_get_dst(msg)), idiagnl_msg_get_tcpinfo(msg))); } return results; }
static void check_addresses (NMIP6Device *device) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; /* Reset address information */ device->has_linklocal = FALSE; device->has_nonlinklocal = FALSE; /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s/%d", device->iface, buf, rtnl_addr_get_prefixlen (rtnladdr)); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device_set_state (device, NM_IP6_DEVICE_GOT_LINK_LOCAL); device->has_linklocal = TRUE; } else { if (device->state == NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device_set_state (device, NM_IP6_DEVICE_GOT_ADDRESS); device->has_nonlinklocal = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !device->has_linklocal) device_set_state (device, NM_IP6_DEVICE_UNCONFIGURED); nm_log_dbg (LOGD_IP6, "(%s): addresses checked (state %s)", device->iface, state_to_string (device->state)); }
void netlink_wrapper::notify_cache_entries(struct nl_cache* cache) { nl_logfunc("--->netlink_wrapper::notify_cache_entries"); g_nl_rcv_arg.msghdr = NULL; nl_object* obj = nl_cache_get_first(m_cache_neigh); while (obj) { nl_object_get(obj); neigh_cache_callback(cache, obj, 0); nl_object_put(obj); obj = nl_cache_get_next(obj); } nl_logfunc("<---netlink_wrapper::notify_cache_entries"); }
TError TNlLink::WaitAddress(int timeout_s) { struct nl_cache *cache; int ret; L() << "Wait for autoconf at " << GetDesc() << std::endl; ret = rtnl_addr_alloc_cache(GetSock(), &cache); if (ret < 0) return Nl->Error(ret, "Cannot allocate addr cache"); do { for (auto obj = nl_cache_get_first(cache); obj; obj = nl_cache_get_next(obj)) { auto addr = (struct rtnl_addr *)obj; if (!rtnl_addr_get_local(addr) || rtnl_addr_get_ifindex(addr) != GetIndex() || rtnl_addr_get_family(addr) != AF_INET6 || rtnl_addr_get_scope(addr) >= RT_SCOPE_LINK || (rtnl_addr_get_flags(addr) & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))) continue; L() << "Got " << TNlAddr(rtnl_addr_get_local(addr)).Format() << " at " << GetDesc() << std::endl; nl_cache_free(cache); return TError::Success(); } usleep(1000000); ret = nl_cache_refill(GetSock(), cache); if (ret < 0) return Nl->Error(ret, "Cannot refill address cache"); } while (--timeout_s > 0); nl_cache_free(cache); return TError(EError::Unknown, "Network autoconf timeout"); }
int netlink_wrapper::get_neigh(const char* ipaddr, netlink_neigh_info* new_neigh_info) { auto_unlocker lock(m_cache_lock); nl_logfunc("--->netlink_listener::get_neigh"); nl_object* obj; rtnl_neigh* neigh; char addr_str[256]; BULLSEYE_EXCLUDE_BLOCK_START if (!new_neigh_info) { nl_logerr("Illegal argument. user pass NULL neigh_info to fill"); return -1; } BULLSEYE_EXCLUDE_BLOCK_END obj = nl_cache_get_first(m_cache_neigh); while (obj) { nl_object_get(obj); //Acquire a reference on a cache object. cache won't use/free it until calling to nl_object_put(obj) neigh = (rtnl_neigh*) obj; nl_addr* addr = rtnl_neigh_get_dst(neigh); if (addr) { nl_addr2str(addr, addr_str, 255); if (!strcmp(addr_str, ipaddr)) { new_neigh_info->fill(neigh); nl_object_put(obj); nl_logdbg("neigh - DST_IP:%s LLADDR:%s", addr_str, new_neigh_info->lladdr_str.c_str() ); nl_logfunc("<---netlink_listener::get_neigh"); return 1; } } nl_object_put(obj); obj = nl_cache_get_next(obj); } nl_logfunc("<---netlink_listener::get_neigh"); return 0; }
TError TNl::OpenLinks(std::vector<std::shared_ptr<TNlLink>> &links, bool all) { struct nl_cache *cache; int ret; ret = rtnl_link_alloc_cache(GetSock(), AF_UNSPEC, &cache); if (ret < 0) return Error(ret, "Cannot allocate link cache"); for (auto obj = nl_cache_get_first(cache); obj; obj = nl_cache_get_next(obj)) { auto link = (struct rtnl_link *)obj; if (!all && ((rtnl_link_get_flags(link) & (IFF_LOOPBACK | IFF_RUNNING)) != IFF_RUNNING)) continue; auto l = std::make_shared<TNlLink>(shared_from_this(), link); links.push_back(l); } nl_cache_free(cache); return TError::Success(); }
static void nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed) { NMIP6Manager *manager = device->manager; NMIP6ManagerPrivate *priv = NM_IP6_MANAGER_GET_PRIVATE (manager); struct rtnl_addr *rtnladdr; struct nl_addr *nladdr; struct in6_addr *addr; CallbackInfo *info; guint dhcp_opts = IP6_DHCP_OPT_NONE; gboolean found_linklocal = FALSE, found_other = FALSE; nm_log_dbg (LOGD_IP6, "(%s): syncing with netlink (ra_flags 0x%X) (state/target '%s'/'%s')", device->iface, device->ra_flags, state_to_string (device->state), state_to_string (device->target_state)); /* Look for any IPv6 addresses the kernel may have set for the device */ for (rtnladdr = (struct rtnl_addr *) nl_cache_get_first (priv->addr_cache); rtnladdr; rtnladdr = (struct rtnl_addr *) nl_cache_get_next ((struct nl_object *) rtnladdr)) { char buf[INET6_ADDRSTRLEN]; if (rtnl_addr_get_ifindex (rtnladdr) != device->ifindex) continue; nladdr = rtnl_addr_get_local (rtnladdr); if (!nladdr || nl_addr_get_family (nladdr) != AF_INET6) continue; addr = nl_addr_get_binary_addr (nladdr); if (inet_ntop (AF_INET6, addr, buf, INET6_ADDRSTRLEN) > 0) { nm_log_dbg (LOGD_IP6, "(%s): netlink address: %s", device->iface, buf); } if (IN6_IS_ADDR_LINKLOCAL (addr)) { if (device->state == NM_IP6_DEVICE_UNCONFIGURED) device->state = NM_IP6_DEVICE_GOT_LINK_LOCAL; found_linklocal = TRUE; } else { if (device->state < NM_IP6_DEVICE_GOT_ADDRESS) device->state = NM_IP6_DEVICE_GOT_ADDRESS; found_other = TRUE; } } /* There might be a LL address hanging around on the interface from * before in the initial run, but if it goes away later, make sure we * regress from GOT_LINK_LOCAL back to UNCONFIGURED. */ if ((device->state == NM_IP6_DEVICE_GOT_LINK_LOCAL) && !found_linklocal) device->state = NM_IP6_DEVICE_UNCONFIGURED; nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)", device->iface, state_to_string (device->state)); /* We only care about router advertisements if we want a real IPv6 address */ if ( (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->ra_flags & IF_RA_RCVD)) { if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT) device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; if (device->ra_flags & IF_RA_MANAGED) { dhcp_opts = IP6_DHCP_OPT_MANAGED; nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6"); } else if (device->ra_flags & IF_RA_OTHERCONF) { dhcp_opts = IP6_DHCP_OPT_OTHERCONF; nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6"); } } if (!device->addrconf_complete) { /* Managed mode (ie DHCP only) short-circuits automatic addrconf, so * we don't bother waiting for the device's target state to be reached * when the RA requests managed mode. */ if ( (device->state >= device->target_state) || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) { /* device->finish_addrconf_id may currently be a timeout * rather than an idle, so we remove the existing source. */ if (device->finish_addrconf_id) g_source_remove (device->finish_addrconf_id); nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)", device->iface, state_to_string (device->state), dhcp_opts); info = callback_info_new (device, dhcp_opts, TRUE); device->finish_addrconf_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, finish_addrconf, info, (GDestroyNotify) g_free); } } else if (config_changed) { if (!device->config_changed_id) { gboolean success = TRUE; /* If for some reason an RA-provided address disappeared, we need * to make sure we fail the connection as it's no longer valid. */ if ( (device->state == NM_IP6_DEVICE_GOT_ADDRESS) && (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS) && !found_other) { nm_log_dbg (LOGD_IP6, "(%s): RA-provided address no longer valid", device->iface); success = FALSE; } info = callback_info_new (device, dhcp_opts, success); device->config_changed_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, emit_config_changed, info, (GDestroyNotify) g_free); } } }
CAMLprim value ocaml_get_routing_table(value unit) { CAMLparam1(unit); CAMLlocal3( ret, tmp, entry ); struct nl_sock *fd; struct nl_cache *res, *links; struct rtnl_route *it; uint32 i_ip, netmask = 0, mask_len, gw; int i; struct nl_addr *ip; char device_name[IFNAMSIZ]; struct rtnl_nexthop *to; fd = nl_socket_alloc(); if (!fd) { fprintf(stderr, "error nl_socket_alloc\n"); exit(1); } if(nl_connect(fd, NETLINK_ROUTE) < 0) { fprintf(stderr, "error nl_connect\n"); exit(1); } ret = Val_emptylist; if(rtnl_route_alloc_cache(fd, AF_UNSPEC, 0, &res) < 0) { fprintf(stderr, "error rtnl_route_alloc_cache"); exit(1); } if(rtnl_link_alloc_cache (fd, AF_UNSPEC, &links) < 0) { fprintf(stderr, "error rtnl_link_alloc_cache"); exit(1); } it = (struct rtnl_route *)nl_cache_get_first(res); for(; it != NULL; it = (struct rtnl_route *) nl_cache_get_next((struct nl_object *)it) ) { if(rtnl_route_get_family (it) == AF_INET) { ip = rtnl_route_get_dst(it); i_ip = ntohl(*(int *)nl_addr_get_binary_addr(ip)); mask_len = nl_addr_get_prefixlen(ip); for(i = 0; i < 32; i++) netmask = (netmask << 1) + (i< mask_len?1:0); to = rtnl_route_nexthop_n(it, 0); rtnl_link_i2name(links, rtnl_route_nh_get_ifindex(to), device_name, IFNAMSIZ); if ( rtnl_route_nh_get_gateway (to) != NULL) gw = ntohl(*(int *)nl_addr_get_binary_addr( rtnl_route_nh_get_gateway (to))); else gw = 0; /*printf("src ip:%x mask:%x gw:%x dev:%s\n", i_ip, netmask, */ /*gw, device_name);*/ entry = caml_alloc(7,0); Store_field(entry, 0, Val_int(i_ip & 0xFFFF)); Store_field(entry, 1, Val_int(i_ip >> 16)); Store_field(entry, 2, Val_int(netmask & 0xFFFF)); Store_field(entry, 3, Val_int(netmask >> 16)); Store_field(entry, 4, Val_int(gw & 0xFFFF)); Store_field(entry, 5, Val_int(gw >> 16)); Store_field(entry, 6, caml_copy_string(device_name)); // store in list tmp = caml_alloc(2, 0); Store_field( tmp, 0, entry); // head Store_field( tmp, 1, ret); // tail ret = tmp; } }