tb_ifaddrs_interface_ref_t tb_ifaddrs_interface(tb_ifaddrs_ref_t ifaddrs, tb_char_t const* name, tb_bool_t reload) { // check tb_assert_and_check_return_val(ifaddrs && name, tb_null); // the iterator tb_iterator_ref_t iterator = tb_ifaddrs_itor(ifaddrs, reload); tb_assert_and_check_return_val(iterator, tb_null); // reload it if the cached interfaces is empty if (!reload && !tb_iterator_size(iterator)) iterator = tb_ifaddrs_itor(ifaddrs, tb_true); // ok return tb_ifaddrs_interface_find(iterator, name); }
static tb_void_t tb_ifaddrs_interface_load4(tb_list_ref_t interfaces) { // check tb_assert_and_check_return(interfaces); // done PIP_ADAPTER_INFO adapter_info = tb_null; do { // make the adapter info adapter_info = tb_malloc0_type(IP_ADAPTER_INFO); tb_assert_and_check_break(adapter_info); // get the real adapter info size ULONG size = sizeof(IP_ADAPTER_INFO); if (tb_iphlpapi()->GetAdaptersInfo(adapter_info, &size) == ERROR_BUFFER_OVERFLOW) { // grow the adapter info buffer adapter_info = (PIP_ADAPTER_INFO)tb_ralloc(adapter_info, size); tb_assert_and_check_break(adapter_info); // reclear it tb_memset(adapter_info, 0, size); } // get the adapter info if (tb_iphlpapi()->GetAdaptersInfo(adapter_info, &size) != NO_ERROR) break; // done PIP_ADAPTER_INFO adapter = adapter_info; while (adapter) { // check tb_assert(adapter->AdapterName); /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, adapter->AdapterName); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // save flags if (adapter->Type == MIB_IF_TYPE_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save hwaddr if (adapter->AddressLength == sizeof(interface->hwaddr.u8)) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; tb_memcpy(interface->hwaddr.u8, adapter->Address, sizeof(interface->hwaddr.u8)); } // save ipaddrs PIP_ADDR_STRING ipAddress = &adapter->IpAddressList; while (ipAddress && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) != TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) { // done tb_ipaddr_t ipaddr; if ( ipAddress->IpAddress.String && tb_ipaddr_ip_cstr_set(&ipaddr, ipAddress->IpAddress.String, TB_IPADDR_FAMILY_NONE)) { if (ipaddr.family == TB_IPADDR_FAMILY_IPV4) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } else if (ipaddr.family == TB_IPADDR_FAMILY_IPV6) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } } // the next ipAddress = ipAddress->Next; } // new interface? save it if ( interface == &interface_new && interface->flags) { // save interface name interface->name = tb_strdup(adapter->AdapterName); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } // the next adapter adapter = adapter->Next; } } while (0); // exit the adapter info if (adapter_info) tb_free(adapter_info); adapter_info = tb_null; }
static tb_void_t tb_ifaddrs_interface_load6(tb_list_ref_t interfaces) { // check tb_assert_and_check_return(interfaces); // done PIP_ADAPTER_ADDRESSES addresses = tb_null; do { // make the addresses addresses = (PIP_ADAPTER_ADDRESSES)tb_malloc0_type(IP_ADAPTER_ADDRESSES); tb_assert_and_check_break(addresses); // get the real adapter info size ULONG size = sizeof(IP_ADAPTER_ADDRESSES); if (tb_iphlpapi()->GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_DNS_SERVER, tb_null, addresses, &size) == ERROR_BUFFER_OVERFLOW) { // grow the adapter info buffer addresses = (PIP_ADAPTER_ADDRESSES)tb_ralloc(addresses, size); tb_assert_and_check_break(addresses); // reclear it tb_memset(addresses, 0, size); } // get the addresses if (tb_iphlpapi()->GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_DNS_SERVER, tb_null, addresses, &size) != NO_ERROR) break; // done PIP_ADAPTER_ADDRESSES address = addresses; while (address) { // check tb_assert(address->AdapterName); /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, address->AdapterName); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // save flags if (address->IfType == IF_TYPE_SOFTWARE_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save hwaddr if (address->PhysicalAddressLength == sizeof(interface->hwaddr.u8)) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; tb_memcpy(interface->hwaddr.u8, address->PhysicalAddress, sizeof(interface->hwaddr.u8)); } // save ipaddrs PIP_ADAPTER_UNICAST_ADDRESS ipAddress = address->FirstUnicastAddress; while (ipAddress && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) != TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) { // done tb_ipaddr_t ipaddr; struct sockaddr_storage* saddr = (struct sockaddr_storage*)ipAddress->Address.lpSockaddr; if (saddr && tb_sockaddr_save(&ipaddr, saddr)) { if (ipaddr.family == TB_IPADDR_FAMILY_IPV4) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } else if (ipaddr.family == TB_IPADDR_FAMILY_IPV6) { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } } // the next ipAddress = ipAddress->Next; } // new interface? save it if ( interface == &interface_new && interface->flags) { // save interface name interface->name = tb_strdup(address->AdapterName); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } // the next address address = address->Next; } } while (0); // exit the addresses if (addresses) tb_free(addresses); addresses = tb_null; }
tb_iterator_ref_t tb_ifaddrs_itor(tb_ifaddrs_ref_t ifaddrs, tb_bool_t reload) { // check tb_list_ref_t interfaces = (tb_list_ref_t)ifaddrs; tb_assert_and_check_return_val(interfaces, tb_null); // uses the cached interfaces? tb_check_return_val(reload, (tb_iterator_ref_t)interfaces); // clear interfaces first tb_list_clear(interfaces); // query the list of interfaces. struct ifaddrs* list = tb_null; if (!getifaddrs(&list) && list) { #if 0 // init sock tb_long_t sock = socket(AF_INET, SOCK_DGRAM, 0); #endif // done struct ifaddrs* item = tb_null; for (item = list; item; item = item->ifa_next) { // check tb_check_continue(item->ifa_addr && item->ifa_name); /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, item->ifa_name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done switch (item->ifa_addr->sa_family) { case AF_INET: { // the address struct sockaddr_storage const* addr = (struct sockaddr_storage const*)item->ifa_addr; // save ipaddr4 tb_ipaddr_t ipaddr4; if (!tb_sockaddr_save(&ipaddr4, addr)) break; interface->ipaddr4 = ipaddr4.u.ipv4; // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; if ((item->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr4)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; #if 0 // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // attempt get the hwaddr struct ifreq ifr; tb_memset(&ifr, 0, sizeof(ifr)); tb_strcpy(ifr.ifr_name, item->ifa_name); if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, ifr.ifr_hwaddr.sa_data, sizeof(interface->hwaddr.u8)); } } #endif // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case AF_INET6: { // the address struct sockaddr_storage const* addr = (struct sockaddr_storage const*)item->ifa_addr; // save ipaddr6 tb_ipaddr_t ipaddr6; if (!tb_sockaddr_save(&ipaddr6, addr)) break; interface->ipaddr6 = ipaddr6.u.ipv6; // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; if ((item->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr6)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; #if 0 // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // attempt get the hwaddr struct ifreq ifr; tb_memset(&ifr, 0, sizeof(ifr)); tb_strcpy(ifr.ifr_name, item->ifa_name); if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, ifr.ifr_hwaddr.sa_data, sizeof(interface->hwaddr.u8)); } } #endif // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case AF_PACKET: { // the address struct sockaddr_ll const* addr = (struct sockaddr_ll const*)item->ifa_addr; // check tb_check_break(addr->sll_halen == sizeof(interface->hwaddr.u8)); // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, addr->sll_addr, sizeof(interface->hwaddr.u8)); // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } } break; default: { // trace tb_trace_d("unknown family: %d", item->ifa_addr->sa_family); } break; } } #if 0 // exit socket if (sock) close(sock); sock = 0; #endif // exit the interface list freeifaddrs(list); } // ok? return (tb_iterator_ref_t)interfaces; }
static tb_void_t tb_ifaddrs_interface_done_hwaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_IFNAME: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFLA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFLA_ADDRESS: { // no hwaddr? if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // check tb_check_break(rta_data_size == sizeof(interface->hwaddr.u8)); // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; if (info->ifa_flags & IFF_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save hwaddr tb_memcpy(interface->hwaddr.u8, rta_data, sizeof(interface->hwaddr.u8)); // trace tb_trace_d("name: %s, hwaddr: %{hwaddr}", name, &interface->hwaddr); // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } } break; case IFLA_IFNAME: case IFLA_BROADCAST: case IFLA_STATS: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }
static tb_void_t tb_ifaddrs_interface_done_ipaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // must be not link tb_assert_and_check_return(info->ifa_family != AF_PACKET); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFA_LABEL: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: { // make ipaddr tb_ipaddr_t ipaddr; if (!tb_ifaddrs_netlink_ipaddr_save(&ipaddr, info->ifa_family, info->ifa_index, rta_data)) break; // save flags if ((info->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save ipaddr switch (tb_ipaddr_family(&ipaddr)) { case TB_IPADDR_FAMILY_IPV4: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } break; case TB_IPADDR_FAMILY_IPV6: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } break; default: break; } // trace tb_trace_d("name: %s, ipaddr: %{ipaddr}", name, &ipaddr); // new interface? save it if (tb_ipaddr_family(&ipaddr) && interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case IFA_LABEL: case IFA_BROADCAST: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }