// clang++ -std=c++23 -o ifprobe ifprobe.cpp && ./ifprobe #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int open_bpf() { for ( int i = 0; i < 256; ++i ) { std::string p = "/dev/bpf" + std::to_string( i ); int fd = open( p.c_str(), O_RDWR ); if ( fd != -1 ) return fd; if ( errno != EBUSY ) break; } return -1; } static const char* functional_type_name( unsigned t ) { switch ( t ) { case IFRTYPE_FUNCTIONAL_LOOPBACK: return "LOOPBACK"; case IFRTYPE_FUNCTIONAL_WIRED: return "WIRED"; case IFRTYPE_FUNCTIONAL_WIFI_INFRA: return "WIFI_INFRA"; case IFRTYPE_FUNCTIONAL_WIFI_AWDL: return "WIFI_AWDL"; case IFRTYPE_FUNCTIONAL_CELLULAR: return "CELLULAR"; default: return "UNKNOWN"; } } static size_t sockaddr_aligned_size(const sockaddr* address) { if (address->sa_len == 0) return sizeof(long); return (address->sa_len + sizeof(long) - 1) & ~(sizeof(long) - 1); } static void print_sysctl_mac(const char* name) { const unsigned int index = if_nametoindex(name); if (index == 0) { printf(" sysctl_mac="); return; } int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, static_cast(index) }; size_t length = 0; if (sysctl(mib, 6, nullptr, &length, nullptr, 0) != 0) { printf(" sysctl_mac=", errno); return; } std::vector buffer(length); if (sysctl(mib, 6, buffer.data(), &length, nullptr, 0) != 0) { printf(" sysctl_mac=", errno); return; } auto* message = reinterpret_cast(buffer.data()); const auto* address = reinterpret_cast( message + 1); for (int address_index = 0; address_index < RTAX_MAX; ++address_index) { if ((message->ifm_addrs & (1 << address_index)) == 0) continue; if (address_index == RTAX_IFP && address->sa_family == AF_LINK) { auto* link_address = reinterpret_cast(address); if (link_address->sdl_alen == 6) { const auto* mac = reinterpret_cast( LLADDR(link_address)); printf(" sysctl_mac=%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return; } } address = reinterpret_cast( reinterpret_cast(address) + sockaddr_aligned_size(address)); } printf(" sysctl_mac="); } int main() { ifaddrs* ifap = nullptr; if ( getifaddrs( &ifap ) != 0 ) return 1; int probe = socket( AF_INET, SOCK_DGRAM, 0 ); for ( ifaddrs* p = ifap; p; p = p->ifa_next ) { if ( !p->ifa_addr || p->ifa_addr->sa_family != AF_LINK ) continue; auto* dl = reinterpret_cast< sockaddr_dl* >( p->ifa_addr ); unsigned ftype = 0; ifreq fr{}; strncpy( fr.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( probe, SIOCGIFFUNCTIONALTYPE, &fr ) == 0 ) ftype = fr.ifr_ifru.ifru_functional_type; // BIOCGDLT is the decisive check: DLT_EN10MB means our 14-byte Ethernet header is correct framing. int dlt = -1; int fd = open_bpf(); if ( fd >= 0 ) { ifreq br{}; strncpy( br.ifr_name, p->ifa_name, IFNAMSIZ - 1 ); if ( ioctl( fd, BIOCSETIF, &br ) == 0 ) ioctl( fd, BIOCGDLT, &dlt ); close( fd ); } printf( "%-10s maclen=%-2u ftype=%-11s dlt=%-3d up=%d running=%d ", p->ifa_name, dl->sdl_alen, functional_type_name( ftype ), dlt, ( p->ifa_flags & IFF_UP ) != 0, ( p->ifa_flags & IFF_RUNNING ) != 0 ); print_sysctl_mac(p->ifa_name); printf("\n"); } close( probe ); freeifaddrs( ifap ); }