void netlink_neigh_info::fill(struct rtnl_neigh* neigh) { if (!neigh) return; nl_addr* addr; char addr_str[ADDR_MAX_STR_LEN + 1]; addr = rtnl_neigh_get_dst(neigh); if (addr) { dst_addr_str = nl_addr2str(addr, addr_str, ADDR_MAX_STR_LEN); dst_addr = (unsigned char*)nl_addr_get_binary_addr(addr); dst_addr_len = nl_addr_get_len(addr); } addr = rtnl_neigh_get_lladdr(neigh); if (addr) { lladdr_str = nl_addr2str(addr, addr_str, ADDR_MAX_STR_LEN); lladdr = (unsigned char*)nl_addr_get_binary_addr(addr); lladdr_len = nl_addr_get_len(addr); } //addr_family = rtnl_neigh_get_family(neigh); flags = rtnl_neigh_get_flags(neigh); ifindex = rtnl_neigh_get_ifindex(neigh); state = rtnl_neigh_get_state(neigh); type = rtnl_neigh_get_type(neigh); }
void nl_bridge::add_neigh_to_fdb(rtnl_neigh *neigh) { assert(sw); assert(neigh); uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); if (port == 0) { VLOG(1) << __FUNCTION__ << ": unknown port for neigh " << OBJ_CAST(neigh); return; } nl_addr *mac = rtnl_neigh_get_lladdr(neigh); int vlan = rtnl_neigh_get_vlan(neigh); bool permanent = true; // for sure this is master (sw bridged) if (rtnl_neigh_get_master(neigh) && !(rtnl_neigh_get_flags(neigh) & NTF_MASTER)) { rtnl_neigh_set_flags(neigh, NTF_MASTER); } // check if entry already exists in cache if (is_mac_in_l2_cache(neigh)) { permanent = false; } rofl::caddress_ll _mac((uint8_t *)nl_addr_get_binary_addr(mac), nl_addr_get_len(mac)); LOG(INFO) << __FUNCTION__ << ": add mac=" << _mac << " to bridge " << rtnl_link_get_name(bridge) << " on port=" << port << " vlan=" << (unsigned)vlan << ", permanent=" << permanent; LOG(INFO) << __FUNCTION__ << ": object: " << OBJ_CAST(neigh); sw->l2_addr_add(port, vlan, _mac, true, permanent); }
static void get_neigh_cb_event(struct nl_object *obj, void *arg) { struct get_neigh_handler *neigh_handler = (struct get_neigh_handler *)arg; /* assumed serilized callback (no parallel execution of function) */ if (nl_object_match_filter( obj, (struct nl_object *)neigh_handler->filter_neigh)) { struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj; /* check that we didn't set it already */ if (neigh_handler->found_ll_addr == NULL) { if (rtnl_neigh_get_lladdr(neigh) == NULL) return; neigh_handler->found_ll_addr = nl_addr_clone(rtnl_neigh_get_lladdr(neigh)); } } }
static struct nl_addr *get_neigh_mac(struct get_neigh_handler *neigh_handler) { struct rtnl_neigh *neigh; struct nl_addr *ll_addr = NULL; /* future optimization - if link local address - parse address and * return mac now instead of doing so after the routing CB. This * is of course referred to GIDs */ neigh = rtnl_neigh_get(neigh_handler->neigh_cache, neigh_handler->oif, neigh_handler->dst); if (neigh == NULL) return NULL; ll_addr = rtnl_neigh_get_lladdr(neigh); if (NULL != ll_addr) ll_addr = nl_addr_clone(ll_addr); rtnl_neigh_put(neigh); return ll_addr; }
void nl_bridge::remove_neigh_from_fdb(rtnl_neigh *neigh) { assert(sw); nl_addr *addr = rtnl_neigh_get_lladdr(neigh); if (nl_addr_cmp(rtnl_link_get_addr(bridge), addr) == 0) { // ignore ll addr of bridge on slave return; } // lookup l2_cache as well std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> n_lookup( NEIGH_CAST(nl_cache_search(l2_cache.get(), OBJ_CAST(neigh))), rtnl_neigh_put); if (n_lookup) { nl_cache_remove(OBJ_CAST(n_lookup.get())); } const uint32_t port = nl->get_port_id(rtnl_neigh_get_ifindex(neigh)); rofl::caddress_ll mac((uint8_t *)nl_addr_get_binary_addr(addr), nl_addr_get_len(addr)); sw->l2_addr_remove(port, rtnl_neigh_get_vlan(neigh), mac); }
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); } }
int main(int argc, char *argv[]) { struct nl_sock *nl_sock; struct nl_cache *link_cache; int ifindex; int ret = 0; int err = 0; if (argc < 2) { printf("%s ip gw on/off tip\n", argv[0]); return -1; } //link if (err = rtnl_route_read_table_names(ROUTE_TABLE)) { printf("failed to read %s. err = %s\n", ROUTE_TABLE, nl_geterror(err)); return -1;; } nl_sock = nl_socket_alloc(); if (NULL == nl_sock) { printf("failed to alloc netlink handler.\n"); return -1; } if (err = nl_connect(nl_sock, NETLINK_ROUTE)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } if (err = rtnl_link_alloc_cache(nl_sock, AF_INET, &link_cache)) { printf("failed to allocate link cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } ifindex = rtnl_link_name2i(link_cache, NAME); if (0 == ifindex) { printf("%s - failed to find.\n", NAME); ret = -1; goto release_link_cache; } struct rtnl_link * link = rtnl_link_get(link_cache, ifindex); if (link == NULL) { printf("can't get link.\n"); ret = -1; goto release_link_cache; } //rtnl_link_get_by_name struct nl_addr *lladdr = rtnl_link_get_addr(link); if (NULL == lladdr || AF_LLC != nl_addr_get_family(lladdr)) { printf("failed to get MAC\n"); ret = -1; goto release_link; } uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); //addr struct nl_cache * addr_cache; if (err = rtnl_addr_alloc_cache(nl_sock, &addr_cache)) { printf("fail to get addr_cache\n"); ret = -1; goto release_link; } struct rtnl_addr *addr = rtnl_addr_alloc(); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); int prefixlen = 16; nl_cache_foreach_filter(addr_cache, (struct nl_object *)addr, get_ip, &prefixlen); nl_cache_free(addr_cache); uint32_t ipaddr = inet_addr(argv[1]); struct nl_addr * local = nl_addr_build(AF_INET, &ipaddr, sizeof(ipaddr)); rtnl_addr_set_local(addr, local); rtnl_addr_set_ifindex(addr, ifindex); rtnl_addr_set_family(addr, AF_INET); rtnl_addr_set_prefixlen(addr, 32); if (!strcmp(argv[2], "on")) { if (err = rtnl_addr_add(nl_sock, addr, 0)) { printf("fail to add addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } else { if (err = rtnl_addr_delete(nl_sock, addr, 0)) { printf("fail to del addr %s\n", nl_geterror(err)); ret = -1; goto release_addr; } } //neigh struct nl_cache * neigh_cache; if (err = rtnl_neigh_alloc_cache(nl_sock, &neigh_cache)) { printf("failed to allocate neighbor cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } uint32_t gw = inet_addr(argv[3]); struct nl_addr * gw_addr = nl_addr_build(AF_INET, &gw, sizeof(gw)); struct rtnl_neigh * neigh = rtnl_neigh_get(neigh_cache, ifindex, gw_addr); if (neigh) { // It's optional struct nl_addr * lladdr = rtnl_neigh_get_lladdr(neigh); if (lladdr) { uint8_t mac_address[ETHER_ADDR_LEN]; memcpy(mac_address, nl_addr_get_binary_addr(lladdr), ETHER_ADDR_LEN); printf("gw %02X:%02X:%02X:%02X:%02X:%02X\n", mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5]); } } nl_addr_put(gw_addr); //route struct nl_cache *route_cache; if (err = rtnl_route_alloc_cache(nl_sock, AF_INET, 0, &route_cache)) { printf("failed to allocate route cache. err = %s\n", nl_geterror(err)); ret = -1; goto release_neigh_cache; } struct rtnl_route *route = rtnl_route_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_cache; } nl_cache_foreach_filter(route_cache, OBJ_CAST(route), get_route, NULL); /* struct nl_sock *nl_fib_sock; nl_fib_sock = nl_socket_alloc(); if (err = nl_connect(nl_fib_sock, NETLINK_FIB_LOOKUP)) { printf("failed to connect NETLINK_ROUTE. err = %s\n", nl_geterror(err)); ret = -1; goto release_nl; } struct nl_dump_params params = { .dp_fd = stdout, .dp_type = NL_DUMP_DETAILS, }; struct nl_cache *route_cache = flnl_result_alloc_cache(); struct flnl_request *req = flnl_request_alloc(); struct nl_addr * taddr; err = nl_addr_parse(argv[4], AF_INET, &taddr); if (err) { printf("failed to get taddr. err = %s\n", nl_geterror(err)); ret = -1; goto release_route; } int table = RT_TABLE_UNSPEC, scope = RT_SCOPE_UNIVERSE; flnl_request_set_addr(req, taddr); flnl_request_set_table(req, table); flnl_request_set_scope(req, scope); err = flnl_lookup(nl_fib_sock, req, route_cache); if (err) { printf("failed to fib lookup. err = %s\n", nl_geterror(err)); ret = -1; goto release_route_addr; } nl_cache_dump(route_cache, ¶ms); release_route_addr: nl_addr_put(taddr); release_route: nl_cache_free(route_cache); nl_object_put(OBJ_CAST(req)); nl_close(nl_fib_sock); nl_socket_free(nl_fib_sock); */ release_route_cache: nl_cache_free(route_cache); release_neigh_cache: nl_cache_free(neigh_cache); release_addr: nl_addr_put(local); rtnl_addr_put(addr); release_link: rtnl_link_put(link); release_link_cache: nl_cache_free(link_cache); release_nl: nl_close(nl_sock); nl_socket_free(nl_sock); return ret; }
void nl_bridge::update_access_ports(rtnl_link *vxlan_link, rtnl_link *br_link, const uint16_t vid, const uint32_t tunnel_id, const std::deque<rtnl_link *> &bridge_ports, bool add) { // XXX pvid is currently not taken into account for (auto _br_port : bridge_ports) { auto br_port_vlans = rtnl_link_bridge_get_port_vlan(_br_port); if (rtnl_link_get_ifindex(vxlan_link) == rtnl_link_get_ifindex(_br_port)) continue; if (br_port_vlans == nullptr) continue; if (!is_vid_set(vid, br_port_vlans->vlan_bitmap)) continue; bool untagged = is_vid_set(vid, br_port_vlans->untagged_bitmap); int ifindex = rtnl_link_get_ifindex(_br_port); uint32_t pport_no = nl->get_port_id(ifindex); if (pport_no == 0) { LOG(WARNING) << __FUNCTION__ << ": ignoring unknown port " << OBJ_CAST(_br_port); continue; } rtnl_link *link = nl->get_link(rtnl_link_get_ifindex(_br_port), AF_UNSPEC); VLOG(2) << __FUNCTION__ << ": vid=" << vid << ", untagged=" << untagged << ", tunnel_id=" << tunnel_id << ", add=" << add << ", ifindex=" << ifindex << ", pport_no=" << pport_no << ", port: " << OBJ_CAST(_br_port); if (add) { std::string port_name = std::string(rtnl_link_get_name(_br_port)); // this is no longer a normal bridge interface thus we delete all the // bridging entries sw->l2_addr_remove_all_in_vlan(pport_no, vid); vxlan->create_access_port(_br_port, tunnel_id, port_name, pport_no, vid, untagged, nullptr); auto neighs = get_fdb_entries_of_port(_br_port, vid); for (auto n : neighs) { // ignore ll addr of bridge on slave if (nl_addr_cmp(rtnl_link_get_addr(bridge), rtnl_neigh_get_lladdr(n)) == 0) { continue; } VLOG(3) << ": needs to be updated " << OBJ_CAST(n); vxlan->add_l2_neigh(n, link, br_link); } } else { // delete access port and all bridging entries vxlan->delete_access_port(_br_port, pport_no, vid, true); // XXX FIXME check if we have to add the VLANs again (ingress/egress) } } }