/* * Given an interface name (e.g., eth0), return the MAC address in human * readable format (e.g., 00:11:52:12:D9:A0). Return NULL for no match. */ char *iface_mac2str(char *ifname) { int buflen = 20; char *buf = NULL; struct nl_handle *handle = NULL; struct nl_cache *cache = NULL; struct rtnl_link *link = NULL; struct nl_addr *addr = NULL; if (ifname == NULL) { return NULL; } if ((cache = _iface_get_link_cache(&handle)) == NULL) { return NULL; } if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) { goto mac2str_error2; } if ((addr = rtnl_link_get_addr(link)) == NULL) { goto mac2str_error3; } if ((buf = calloc(sizeof(char *), buflen)) == NULL) { goto mac2str_error4; } if ((buf = nl_addr2str(addr, buf, buflen)) != NULL) { buf = str2upper(buf); } mac2str_error4: nl_addr_destroy(addr); mac2str_error3: rtnl_link_put(link); mac2str_error2: nl_close(handle); nl_handle_destroy(handle); return buf; }
static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp) { struct nl_cache *link_cache; char buf[128]; link_cache = nl_cache_mngt_require_safe("route/link"); nl_dump(dp, "nexthop"); if (nh->ce_mask & NH_ATTR_GATEWAY) nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); if(nh->ce_mask & NH_ATTR_IFINDEX) { if (link_cache) { nl_dump(dp, " dev %s", rtnl_link_i2name(link_cache, nh->rtnh_ifindex, buf, sizeof(buf))); } else nl_dump(dp, " dev %d", nh->rtnh_ifindex); } if (nh->ce_mask & NH_ATTR_WEIGHT) nl_dump(dp, " weight %u", nh->rtnh_weight); if (nh->ce_mask & NH_ATTR_REALMS) nl_dump(dp, " realm %04x:%04x", RTNL_REALM_FROM(nh->rtnh_realms), RTNL_REALM_TO(nh->rtnh_realms)); if (nh->ce_mask & NH_ATTR_FLAGS) nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags, buf, sizeof(buf))); if (link_cache) nl_cache_put(link_cache); }
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; }
static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp) { struct nl_cache *link_cache; char buf[128]; link_cache = nl_cache_mngt_require("route/link"); if (nh->ce_mask & NH_ATTR_GATEWAY) nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar, nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf))); if(nh->ce_mask & NH_ATTR_IFINDEX) { if (link_cache) { nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar, rtnl_link_i2name(link_cache, nh->rtnh_ifindex, buf, sizeof(buf))); } else nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar, nh->rtnh_ifindex); } if (nh->ce_mask & NH_ATTR_WEIGHT) nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar, nh->rtnh_weight); if (nh->ce_mask & NH_ATTR_REALMS) nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar, RTNL_REALM_FROM(nh->rtnh_realms), RTNL_REALM_TO(nh->rtnh_realms)); if (nh->ce_mask & NH_ATTR_FLAGS) nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar, rtnl_route_nh_flags2str(nh->rtnh_flags, buf, sizeof(buf))); }
static int addr_dump_xml(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; char buf[128]; int line = 0; dp_dump_line(p, line++, "<address>\n"); dp_dump_line(p, line++, " <family>%s</family>\n", nl_af2str(addr->a_family, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_LOCAL) dp_dump_line(p, line++, " <local>%s</local>\n", nl_addr2str(addr->a_local, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_PEER) dp_dump_line(p, line++, " <peer>%s</peer>\n", nl_addr2str(addr->a_peer, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_BROADCAST) dp_dump_line(p, line++, " <broadcast>%s</broadcast>\n", nl_addr2str(addr->a_bcast, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_ANYCAST) dp_dump_line(p, line++, " <anycast>%s</anycast>\n", nl_addr2str(addr->a_anycast, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_MULTICAST) dp_dump_line(p, line++, " <multicast>%s</multicast>\n", nl_addr2str(addr->a_multicast, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_PREFIXLEN) dp_dump_line(p, line++, " <prefixlen>%u</prefixlen>\n", addr->a_prefixlen); link_cache = nl_cache_mngt_require("route/link"); if (link_cache) dp_dump_line(p, line++, " <device>%s</device>\n", rtnl_link_i2name(link_cache, addr->a_ifindex, buf, sizeof(buf))); else dp_dump_line(p, line++, " <device>%u</device>\n", addr->a_ifindex); if (addr->a_mask & ADDR_ATTR_SCOPE) dp_dump_line(p, line++, " <scope>%s</scope>\n", rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); if (addr->a_mask & ADDR_ATTR_LABEL) dp_dump_line(p, line++, " <label>%s</label>\n", addr->a_label); rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); if (buf[0]) dp_dump_line(p, line++, " <flags>%s</flags>\n", buf); if (addr->a_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; dp_dump_line(p, line++, " <cacheinfo>\n"); dp_dump_line(p, line++, " <valid>%s</valid>\n", ci->aci_valid == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_valid * 1000, buf, sizeof(buf))); dp_dump_line(p, line++, " <prefered>%s</prefered>\n", ci->aci_prefered == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_prefered * 1000, buf, sizeof(buf))); dp_dump_line(p, line++, " <created>%s</created>\n", nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, buf, sizeof(buf))); dp_dump_line(p, line++, " <last-update>%s</last-update>\n", nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, buf, sizeof(buf))); dp_dump_line(p, line++, " </cacheinfo>\n"); } dp_dump_line(p, line++, "</address>\n"); return line; }
static void nl_ihandler_cb(struct incident *i, void *ctx) { g_debug("%s i %p ctx %p", __PRETTY_FUNCTION__, i, ctx); struct connection *con; incident_value_con_get(i, "con", &con); char *remote = con->remote.ip_string; char *local = con->local.ip_string; char *prefix = "::ffff:"; if( strncmp(local, prefix, strlen(prefix)) == 0) local += strlen(prefix); if( strncmp(remote, prefix, strlen(prefix)) == 0) remote += strlen(prefix); int ifindex; int err; { g_debug("local addr %s remote addr %s", local, remote); struct rtnl_addr *addr = rtnl_addr_alloc(); struct nl_addr *a; if ( ( err = nl_addr_parse(local, AF_UNSPEC, &a)) != 0 ) g_critical("could not parse addr %s (%s)", local, nl_geterror(err)); rtnl_addr_set_local(addr, a); nl_addr_put(a); struct rtnl_addr *res = NULL; nl_cache_foreach_filter(nl_runtime.addr_cache, OBJ_CAST(addr), cache_lookup_cb, &res); g_critical("LOCAL RTNL_ADDR %p", res); /* struct nl_dump_params params = { .dp_type = NL_DUMP_LINE, .dp_fd = stdout, }; nl_cache_dump_filter(nl_runtime.addr_cache, ¶ms, OBJ_CAST(addr)); */ ifindex = rtnl_addr_get_ifindex(res); } struct rtnl_neigh *res = NULL; { struct rtnl_neigh *neigh = rtnl_neigh_alloc(); rtnl_neigh_set_ifindex(neigh, ifindex); struct nl_addr *a; if ( ( err = nl_addr_parse(remote, AF_UNSPEC, &a)) != 0 ) g_critical("could not parse addr %s (%s)", remote, nl_geterror(err)); rtnl_neigh_set_dst(neigh, a); nl_addr_put(a); nl_cache_foreach_filter(nl_runtime.neigh_cache, OBJ_CAST(neigh), cache_lookup_cb, &res); } if( res ) { g_critical("GOT NEIGH %p", res); struct nl_addr *lladdr = rtnl_neigh_get_lladdr(res); char buf[123]; nl_addr2str(lladdr, buf, sizeof(buf)); g_critical("GOT NEIGH %s", buf); struct incident *i = incident_new("dionaea.module.nl.connection.info.mac"); incident_value_string_set(i, "mac", g_string_new(buf)); incident_value_con_set(i, "con", con); incident_report(i); incident_free(i); } }
static void nl_obj_input(struct nl_object *obj, void *arg) { struct _obj { NLHDR_COMMON }; struct _obj *o = (struct _obj *)obj; if( o->ce_msgtype == RTM_NEWLINK || o->ce_msgtype == RTM_DELLINK ) { struct rtnl_link *link = (struct rtnl_link *)obj; struct nl_addr *a = rtnl_link_get_addr(link); char buf[123]; nl_addr2str(a, buf, sizeof(buf)); int ifindex = rtnl_link_get_ifindex(link); bool active = rtnl_link_get_flags(link) & IFF_UP; char *iface = rtnl_link_get_name(link); if( o->ce_msgtype == RTM_NEWLINK ) { struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( nla == NULL ) { g_critical("LINK NEW %s %i", iface, ifindex); struct link_addr *nla = link_addr_new(iface, ifindex, active); g_hash_table_insert(nl_runtime.link_addr_cache, &nla->ifindex, nla); }else { g_critical("LINK CHANGE %s %i", iface, ifindex); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, nla->addrs); if( active != nla->active ) { while( g_hash_table_iter_next(&iter, &key, &value) ) { struct incident *i; if( active ) { g_critical("LINK UP"); i = incident_new("dionaea.module.nl.addr.new"); }else { g_critical("LINK DOWN"); i = incident_new("dionaea.module.nl.addr.del"); } incident_value_string_set(i, "addr", g_string_new(key)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } nla->active = active; } } }else if( o->ce_msgtype == RTM_DELLINK ) { g_critical("LINK DEL %s %i", iface, ifindex); struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); g_hash_table_remove(nl_runtime.link_addr_cache, &ifindex); link_addr_free(nla); } }else if( o->ce_msgtype == RTM_NEWADDR || o->ce_msgtype == RTM_DELADDR ) { char buf[128]; struct rtnl_addr *addr = (struct rtnl_addr *)obj; struct nl_addr *a = rtnl_addr_get_local(addr); int ifindex = rtnl_addr_get_ifindex(addr); nl_addr2str(a, buf, 128); char *slash; if( (slash = strstr(buf, "/")) != NULL) *slash = '\0'; char *saddr = NULL; struct link_addr *nla = g_hash_table_lookup(nl_runtime.link_addr_cache, &ifindex); if( !nla ) return; if( o->ce_msgtype == RTM_NEWADDR ) { if( g_hash_table_lookup(nla->addrs, buf) == NULL ) { g_warning("NEW ADDR %s!", buf); saddr = g_strdup(buf); g_hash_table_insert(nla->addrs, saddr, saddr); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.new"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } } }else if( o->ce_msgtype == RTM_DELADDR ) { if( ( saddr = g_hash_table_lookup(nla->addrs, buf) ) != NULL ) { g_warning("DEL ADDR! %s", buf); if( nla->active ) { struct incident *i = incident_new("dionaea.module.nl.addr.del"); incident_value_string_set(i, "addr", g_string_new(saddr)); incident_value_string_set(i, "iface", g_string_new(nla->iface)); incident_value_int_set(i, "scope", nla->ifindex); incident_report(i); incident_free(i); } g_hash_table_remove(nla->addrs, buf); g_free(saddr); } } } /* struct nl_dump_params dp = { .dp_type = NL_DUMP_STATS, .dp_fd = stdout, .dp_dump_msgtype = 1, }; nl_object_dump(obj, &dp); struct nl_dump_params params = { .dp_type = NL_DUMP_LINE, .dp_fd = stdout, .dp_prefix = 1, }; g_debug("addr cache"); nl_cache_dump(nl_runtime.addr_cache, ¶ms); g_debug("arp cache"); nl_cache_dump(nl_runtime.neigh_cache, ¶ms); g_debug("link cache"); nl_cache_dump(nl_runtime.link_cache, ¶ms); */ }
static void route_proc_cb(struct nl_object *c, void *arg) { struct ip_lookup_res *res = (struct ip_lookup_res*) arg; struct rtnl_route *route = (struct rtnl_route *) c; struct nl_cache *link_cache; struct nl_addr *addr; struct rtnl_nexthop *nh; int prefix_len; int oif; char buf[64]; link_cache = nl_cache_mngt_require("route/link"); addr = rtnl_route_get_dst(route); if (addr) { printf("%s", nl_addr2str(addr, buf, sizeof(buf))); res->dstaddr = *(uint32_t *) nl_addr_get_binary_addr(addr); } prefix_len = rtnl_route_get_dst_len(route); if (prefix_len) printf("/%d ", prefix_len); else printf("default "); addr = rtnl_route_get_src(route); if (addr) printf("src %s ", nl_addr2str(addr, buf, sizeof(buf))); addr = rtnl_route_get_pref_src(route); if (addr) printf("preferred src %s ", nl_addr2str(addr, buf, sizeof(buf))); addr = rtnl_route_get_gateway(route); if (addr) { printf("via %s ", nl_addr2str(addr, buf, sizeof(buf))); res->nh_addr = *(uint32_t*) nl_addr_get_binary_addr(addr); } else { res->nh_addr = 0; } oif = rtnl_route_get_oif(route); res->oif = oif; if (oif != RTNL_LINK_NOT_FOUND && link_cache) { printf("dev %s ", rtnl_link_i2name(link_cache, oif, buf, sizeof(buf))); rtnl_link_i2name(link_cache, oif, res->oifname, sizeof(res->oifname)); } /* Declaration of rtnl_route_nh_get_gateway() is missing from * include/netlink/route/nexthop.h, there is no way to inspect * each nexthop for gateway information, will just use gateway * info stored in rtnl_route struct. The probem is only present * libnl 1 */ /* nl_list_for_each_entry(nh, rtnl_route_get_nexthops(route), rtnh_list) { } */ printf("\n"); }
void NetlinkManager::netlinkRouteUpdated( struct nl_cache* /*cache*/, struct nl_object* obj, int nlOperation, void* data) { NetlinkManager* nlm = static_cast<NetlinkManager*>(data); std::string operation = nlm->nlOperationToStr(nlOperation); if (operation == "unknown") { VLOG(1) << "Ignoring an unknown route update"; return; } VLOG(2) << "Received a " << operation << " netlink route update message"; struct rtnl_route* route = (struct rtnl_route*)obj; if (rtnl_route_get_type(route) != RTN_UNICAST) { VLOG(1) << "Ignoring non-unicast route update"; return; } struct nl_addr* nlDst = rtnl_route_get_dst(route); const uint8_t ipLen = nl_addr_get_prefixlen(nlDst); char strDst[ipLen]; nl_addr2str(nlDst, strDst, ipLen); int numNexthops = rtnl_route_get_nnexthops(route); if (!numNexthops) { VLOG(0) << "Could not find next hop for route update for " << strDst; struct nl_dump_params dumpParams = initDumpParams(); nl_object_dump((nl_object*)route, &dumpParams); return; } std::vector<BinaryAddress> nexthops; { std::lock_guard<std::mutex> lock(nlm->interfacesMutex_); nexthops = getNextHops(route, ipLen, nlm->monitoredInterfaces_); } if (nexthops.empty()) { VLOG(1) << operation << " Route update for " << strDst << " has no valid nexthop"; return; } if (FLAGS_debug) { VLOG(1) << "Got " << operation << " route update for " << strDst; return; } switch (nlOperation) { case NL_ACT_NEW: { nlm->addRouteViaFbossThrift(nlDst, nexthops); break; } case NL_ACT_DEL: { nlm->deleteRouteViaFbossThrift(nlDst); break; } case NL_ACT_CHANGE: { VLOG(2) << "Not updating state due to unimplemented" << "NL_ACT_CHANGE netlink operation"; break; } default: { VLOG(0) << "Not updating state due to unknown netlink operation " << std::to_string(nlOperation); break; /* NL_ACT_??? */ } } return; }
static int addr_dump_env(struct nl_object *obj, struct nl_dump_params *p) { struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; char buf[128]; int line = 0; dp_dump_line(p, line++, "ADDR_FAMILY=%s\n", nl_af2str(addr->a_family, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_LOCAL) dp_dump_line(p, line++, "ADDR_LOCAL=%s\n", nl_addr2str(addr->a_local, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_PEER) dp_dump_line(p, line++, "ADDR_PEER=%s\n", nl_addr2str(addr->a_peer, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_BROADCAST) dp_dump_line(p, line++, "ADDR_BROADCAST=%s\n", nl_addr2str(addr->a_bcast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_ANYCAST) dp_dump_line(p, line++, "ADDR_ANYCAST=%s\n", nl_addr2str(addr->a_anycast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_MULTICAST) dp_dump_line(p, line++, "ADDR_MULTICAST=%s\n", nl_addr2str(addr->a_multicast, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_PREFIXLEN) dp_dump_line(p, line++, "ADDR_PREFIXLEN=%u\n", addr->a_prefixlen); link_cache = nl_cache_mngt_require("route/link"); dp_dump_line(p, line++, "ADDR_IFINDEX=%u\n", addr->a_ifindex); if (link_cache) dp_dump_line(p, line++, "ADDR_IFNAME=%s\n", rtnl_link_i2name(link_cache, addr->a_ifindex, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_SCOPE) dp_dump_line(p, line++, "ADDR_SCOPE=%s\n", rtnl_scope2str(addr->a_scope, buf, sizeof(buf))); if (addr->ce_mask & ADDR_ATTR_LABEL) dp_dump_line(p, line++, "ADDR_LABEL=%s\n", addr->a_label); rtnl_addr_flags2str(addr->a_flags, buf, sizeof(buf)); if (buf[0]) dp_dump_line(p, line++, "ADDR_FLAGS=%s\n", buf); if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; dp_dump_line(p, line++, "ADDR_CACHEINFO_VALID=%s\n", ci->aci_valid == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_valid * 1000, buf, sizeof(buf))); dp_dump_line(p, line++, "ADDR_CACHEINFO_PREFERED=%s\n", ci->aci_prefered == 0xFFFFFFFFU ? "forever" : nl_msec2str(ci->aci_prefered * 1000, buf, sizeof(buf))); dp_dump_line(p, line++, "ADDR_CACHEINFO_CREATED=%s\n", nl_msec2str(addr->a_cacheinfo.aci_cstamp * 10, buf, sizeof(buf))); dp_dump_line(p, line++, "ADDR_CACHEINFO_LASTUPDATE=%s\n", nl_msec2str(addr->a_cacheinfo.aci_tstamp * 10, buf, sizeof(buf))); } return line; }
static void inet6_dump_details(struct rtnl_link *link, struct nl_dump_params *p, void *data) { struct inet6_data *i6 = data; struct nl_addr *addr; char buf[64], buf2[64]; int i, n = 0; nl_dump_line(p, " ipv6 max-reasm-len %s", nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf))); nl_dump(p, " <%s>\n", inet6_flags2str(i6->i6_flags, buf, sizeof(buf))); nl_dump_line(p, " create-stamp %.2fs reachable-time %s", (double) i6->i6_cacheinfo.tstamp / 100., nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf))); nl_dump(p, " retrans-time %s\n", nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf))); addr = nl_addr_build(AF_INET6, &i6->i6_token, sizeof(i6->i6_token)); nl_dump(p, " token %s\n", nl_addr2str(addr, buf, sizeof(buf))); nl_addr_put(addr); nl_dump(p, " link-local address mode %s\n", rtnl_link_inet6_addrgenmode2str(i6->i6_addr_gen_mode, buf, sizeof(buf))); nl_dump_line(p, " devconf:\n"); nl_dump_line(p, " "); for (i = 0; i < DEVCONF_MAX; i++) { uint32_t value = i6->i6_conf[i]; int x, offset; switch (i) { case DEVCONF_TEMP_VALID_LFT: case DEVCONF_TEMP_PREFERED_LFT: nl_msec2str((uint64_t) value * 1000., buf2, sizeof(buf2)); break; case DEVCONF_RTR_PROBE_INTERVAL: case DEVCONF_RTR_SOLICIT_INTERVAL: case DEVCONF_RTR_SOLICIT_DELAY: nl_msec2str(value, buf2, sizeof(buf2)); break; default: snprintf(buf2, sizeof(buf2), "%u", value); break; } inet6_devconf2str(i, buf, sizeof(buf)); offset = 23 - strlen(buf2); if (offset < 0) offset = 0; for (x = strlen(buf); x < offset; x++) buf[x] = ' '; strncpy(&buf[offset], buf2, strlen(buf2)); nl_dump_line(p, "%s", buf); if (++n == 3) { nl_dump(p, "\n"); nl_dump_line(p, " "); n = 0; } else nl_dump(p, " "); } if (n != 0) nl_dump(p, "\n"); }
static void handle_class(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; struct rdata *rdata = arg; struct rdata ndata = { .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "class", rdata))) return; ndata.parent = e; if (!strcmp(rtnl_tc_get_kind(tc), "htb")) element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc)); find_classes(rtnl_tc_get_handle(tc), &ndata); find_qdiscs(rtnl_tc_get_handle(tc), &ndata); } static void find_qdiscs(uint32_t parent, struct rdata *rdata) { struct rtnl_qdisc *filter; if (!(filter = rtnl_qdisc_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), handle_qdisc, rdata); rtnl_qdisc_put(filter); } static void find_cls(int ifindex, uint32_t parent, struct rdata *rdata) { struct nl_cache *cls_cache; if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0) return; nl_cache_foreach(cls_cache, handle_cls, rdata); nl_cache_free(cls_cache); } static void find_classes(uint32_t parent, struct rdata *rdata) { struct rtnl_class *filter; if (!(filter = rtnl_class_alloc())) return; rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); nl_cache_foreach_filter(class_cache, OBJ_CAST(filter), handle_class, rdata); rtnl_class_put(filter); } static void handle_qdisc(struct nl_object *obj, void *arg) { struct rtnl_tc *tc = (struct rtnl_tc *) obj; struct element *e; struct rdata *rdata = arg; struct rdata ndata = { .level = rdata->level + 1, }; if (!(e = handle_tc_obj(tc, "qdisc", rdata))) return; ndata.parent = e; find_cls(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata); if (rtnl_tc_get_parent(tc) == TC_H_ROOT) { find_cls(rtnl_tc_get_ifindex(tc), TC_H_ROOT, &ndata); find_classes(TC_H_ROOT, &ndata); } find_classes(rtnl_tc_get_handle(tc), &ndata); } static void handle_tc(struct element *e, struct rtnl_link *link) { struct rtnl_qdisc *qdisc; int ifindex = rtnl_link_get_ifindex(link); struct rdata rdata = { .level = 1, .parent = e, }; if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0) return; qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, 0); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_INGRESS); if (qdisc) { handle_qdisc(OBJ_CAST(qdisc), &rdata); rtnl_qdisc_put(qdisc); } nl_cache_free(class_cache); } static void update_link_infos(struct element *e, struct rtnl_link *link) { char buf[64]; snprintf(buf, sizeof(buf), "%u", rtnl_link_get_mtu(link)); element_update_info(e, "MTU", buf); rtnl_link_flags2str(rtnl_link_get_flags(link), buf, sizeof(buf)); element_update_info(e, "Flags", buf); rtnl_link_operstate2str(rtnl_link_get_operstate(link), buf, sizeof(buf)); element_update_info(e, "Operstate", buf); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_ifindex(link)); element_update_info(e, "IfIndex", buf); nl_addr2str(rtnl_link_get_addr(link), buf, sizeof(buf)); element_update_info(e, "Address", buf); nl_addr2str(rtnl_link_get_broadcast(link), buf, sizeof(buf)); element_update_info(e, "Broadcast", buf); rtnl_link_mode2str(rtnl_link_get_linkmode(link), buf, sizeof(buf)); element_update_info(e, "Mode", buf); snprintf(buf, sizeof(buf), "%u", rtnl_link_get_txqlen(link)); element_update_info(e, "TXQlen", buf); nl_af2str(rtnl_link_get_family(link), buf, sizeof(buf)); element_update_info(e, "Family", buf); element_update_info(e, "Alias", rtnl_link_get_ifalias(link) ? : ""); element_update_info(e, "Qdisc", rtnl_link_get_qdisc(link) ? : ""); if (rtnl_link_get_link(link)) { snprintf(buf, sizeof(buf), "%u", rtnl_link_get_link(link)); element_update_info(e, "SlaveOfIndex", buf); } } static void do_link(struct nl_object *obj, void *arg) { struct rtnl_link *link = (struct rtnl_link *) obj; struct element *e, *e_parent = NULL; int i, master_ifindex; if (!cfg_show_all && !(rtnl_link_get_flags(link) & IFF_UP)) { /* FIXME: delete element */ return; } /* Check if the interface is a slave of another interface */ if ((master_ifindex = rtnl_link_get_link(link))) { char parent[IFNAMSIZ+1]; rtnl_link_i2name(link_cache, master_ifindex, parent, sizeof(parent)); e_parent = element_lookup(grp, parent, master_ifindex, NULL, 0); } if (!(e = element_lookup(grp, rtnl_link_get_name(link), rtnl_link_get_ifindex(link), e_parent, ELEMENT_CREAT))) return; if (e->e_flags & ELEMENT_FLAG_CREATED) { if (e->e_parent) e->e_level = e->e_parent->e_level + 1; if (element_set_key_attr(e, "bytes", "packets") || element_set_usage_attr(e, "bytes")) BUG(); /* FIXME: Update link infos every 1s or so */ update_link_infos(e, link); e->e_flags &= ~ELEMENT_FLAG_CREATED; } for (i = 0; i < ARRAY_SIZE(link_attrs); i++) { struct attr_map *m = &link_attrs[i]; uint64_t c_rx = 0, c_tx = 0; int flags = 0; if (m->rxid >= 0) { c_rx = rtnl_link_get_stat(link, m->rxid); flags |= UPDATE_FLAG_RX; } if (m->txid >= 0) { c_tx = rtnl_link_get_stat(link, m->txid); flags |= UPDATE_FLAG_TX; } attr_update(e, m->attrid, c_rx, c_tx, flags); } if (!c_notc) handle_tc(e, link); element_notify_update(e, NULL); element_lifesign(e, 1); } static void netlink_read(void) { int err; if ((err = nl_cache_resync(sock, link_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync link cache: %s\n", nl_geterror(err)); goto disable; } if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) { fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err)); goto disable; } nl_cache_foreach(link_cache, do_link, NULL); return; disable: netlink_ops.m_flags &= ~BMON_MODULE_ENABLED; } static void netlink_shutdown(void) { nl_cache_free(link_cache); nl_cache_free(qdisc_cache); nl_socket_free(sock); }
static void env_dump(struct nl_object *obj, void *arg) { struct nl_dump_params *p = arg; struct rtnl_addr *addr = (struct rtnl_addr *) obj; struct nl_cache *link_cache; struct nl_addr *a; static int index = 0; char buf[128], pfx[32], *s; snprintf(pfx, sizeof(pfx), "ADDR%d", index++); nl_dump_line(p, "%s_FAMILY=%s\n", pfx, nl_af2str(rtnl_addr_get_family(addr), buf, sizeof(buf))); nl_dump_line(p, "%s_LOCAL=%s\n", pfx, nl_addr2str(rtnl_addr_get_local(addr), buf, sizeof(buf))); nl_dump_line(p, "%s_IFINDEX=%u\n", pfx, rtnl_addr_get_ifindex(addr)); link_cache = nl_cache_mngt_require_safe("route/link"); if (link_cache) nl_dump_line(p, "%s_IFNAME=%s\n", pfx, rtnl_link_i2name(link_cache, rtnl_addr_get_ifindex(addr), buf, sizeof(buf))); if ((a = rtnl_addr_get_peer(addr))) nl_dump_line(p, "%s_PEER=%s\n", pfx, nl_addr2str(a, buf, sizeof(buf))); if ((a = rtnl_addr_get_broadcast(addr))) nl_dump_line(p, "%s_BROADCAST=%s\n", pfx, nl_addr2str(a, buf, sizeof(buf))); nl_dump_line(p, "%s_SCOPE=%s\n", pfx, rtnl_scope2str(rtnl_addr_get_scope(addr), buf, sizeof(buf))); if ((s = rtnl_addr_get_label(addr))) nl_dump_line(p, "%s_LABEL=%s\n", pfx, s); rtnl_addr_flags2str(rtnl_addr_get_flags(addr), buf, sizeof(buf)); if (buf[0]) nl_dump_line(p, "%s_FLAGS=%s\n", pfx, buf); nl_dump_line(p, "%s_CACHEINFO_VALID=%u\n", pfx, rtnl_addr_get_valid_lifetime(addr)); if (link_cache) nl_cache_put(link_cache); #if 0 if (addr->ce_mask & ADDR_ATTR_CACHEINFO) { struct rtnl_addr_cacheinfo *ci = &addr->a_cacheinfo; nl_dump_line(p, "ADDR_CACHEINFO_PREFERRED=%u\n", ci->aci_prefered); nl_dump_line(p, "ADDR_CACHEINFO_CREATED=%u\n", ci->aci_cstamp); nl_dump_line(p, "ADDR_CACHEINFO_LASTUPDATE=%u\n", ci->aci_tstamp); } #endif }
static void xfrm_ae_dump_line(struct nl_object *a, struct nl_dump_params *p) { char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5]; struct xfrmnl_ae* ae = (struct xfrmnl_ae *) a; char flags[128], buf[128]; time_t add_time, use_time; struct tm *add_time_tm, *use_time_tm; nl_dump_line(p, "src %s dst %s \n", nl_addr2str(ae->saddr, src, sizeof(src)), nl_addr2str(ae->sa_id.daddr, dst, sizeof(dst))); nl_dump_line(p, "\tproto %s spi 0x%x reqid %u ", nl_ip_proto2str (ae->sa_id.proto, buf, sizeof (buf)), ae->sa_id.spi, ae->reqid); xfrmnl_ae_flags2str(ae->flags, flags, sizeof (flags)); nl_dump_line(p, "flags %s(0x%x) mark mask/value 0x%x/0x%x \n", flags, ae->flags, ae->mark.m, ae->mark.v); nl_dump_line(p, "\tlifetime current: \n"); nl_dump_line(p, "\t\tbytes %llu packets %llu \n", ae->lifetime_cur.bytes, ae->lifetime_cur.packets); if (ae->lifetime_cur.add_time != 0) { add_time = ae->lifetime_cur.add_time; add_time_tm = gmtime (&add_time); strftime (flags, 128, "%Y-%m-%d %H-%M-%S", add_time_tm); } else { sprintf (flags, "%s", "-"); } if (ae->lifetime_cur.use_time != 0) { use_time = ae->lifetime_cur.use_time; use_time_tm = gmtime (&use_time); strftime (buf, 128, "%Y-%m-%d %H-%M-%S", use_time_tm); } else { sprintf (buf, "%s", "-"); } nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", flags, buf); nl_dump_line(p, "\treplay info: \n"); nl_dump_line(p, "\t\tmax age %u max diff %u \n", ae->replay_maxage, ae->replay_maxdiff); nl_dump_line(p, "\treplay state info: \n"); if (ae->replay_state_esn) { nl_dump_line(p, "\t\toseq %u seq %u oseq_hi %u seq_hi %u replay window: %u \n", ae->replay_state_esn->oseq, ae->replay_state_esn->seq, ae->replay_state_esn->oseq_hi, ae->replay_state_esn->seq_hi, ae->replay_state_esn->replay_window); } else { nl_dump_line(p, "\t\toseq %u seq %u bitmap: %u \n", ae->replay_state.oseq, ae->replay_state.seq, ae->replay_state.bitmap); } nl_dump(p, "\n"); }