File indexing completed on 2024-05-12 16:59:53
0001 /* 0002 * SPDX-FileCopyrightText: 2001 Alexander Neundorf <neundorf@kde.org> 0003 * SPDX-FileCopyrightText: 2020 Carl Schwan <carl@carlschwan.eu> 0004 * SPDX-FileCopyrightText: 2021 Harald Sitter <sitter@kde.org> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "networkmodel.h" 0010 0011 #include <arpa/inet.h> 0012 #include <netinet/in.h> 0013 #include <stdio.h> 0014 #include <sys/param.h> 0015 #include <sys/socket.h> 0016 #include <sys/types.h> 0017 #include <unistd.h> 0018 0019 #include "config-nic.h" 0020 0021 #include <array> 0022 0023 #include <KLocalizedString> 0024 0025 #include <QDebug> 0026 #include <QHash> 0027 0028 #include <KPluginFactory> 0029 #include <net/if.h> 0030 #include <sys/ioctl.h> 0031 0032 #include <ifaddrs.h> 0033 #include <netdb.h> 0034 0035 using HostNameArray = std::array<char, NI_MAXHOST>; 0036 0037 QString flags_tos(unsigned int flags); 0038 0039 NetworkModel::NetworkModel(QObject *parent) 0040 : QAbstractListModel(parent) 0041 { 0042 update(); 0043 } 0044 0045 QVariant NetworkModel::data(const QModelIndex &index, int role) const 0046 { 0047 Q_UNUSED(role); 0048 if (index.isValid()) { 0049 const auto nic = m_nics.at(index.row()); 0050 0051 switch (role) { 0052 case NetworkModel::Roles::NameRole: 0053 return nic->name; 0054 case NetworkModel::Roles::AddrRole: 0055 return nic->addr; 0056 case NetworkModel::Roles::NetMaskRole: 0057 return nic->netmask; 0058 case NetworkModel::Roles::TypeRole: 0059 return nic->type; 0060 case NetworkModel::Roles::HWAddrRole: 0061 return nic->HWaddr; 0062 case NetworkModel::Roles::StateRole: 0063 return nic->state; 0064 } 0065 } 0066 return QVariant{}; 0067 } 0068 0069 QHash<int, QByteArray> NetworkModel::roleNames() const 0070 { 0071 return {{NetworkModel::Roles::NameRole, QByteArrayLiteral("name")}, 0072 {NetworkModel::Roles::AddrRole, QByteArrayLiteral("address")}, 0073 {NetworkModel::Roles::NetMaskRole, QByteArrayLiteral("netmask")}, 0074 {NetworkModel::Roles::TypeRole, QByteArrayLiteral("type")}, 0075 {NetworkModel::Roles::HWAddrRole, QByteArrayLiteral("hardwareAddress")}, 0076 {NetworkModel::Roles::StateRole, QByteArrayLiteral("state")}}; 0077 } 0078 0079 int NetworkModel::rowCount(const QModelIndex &parent) const 0080 { 0081 Q_UNUSED(parent) 0082 return m_nics.size(); 0083 } 0084 0085 QList<NetworkModel::MyNIC *> findNICs(); 0086 0087 void NetworkModel::update() 0088 { 0089 beginResetModel(); 0090 m_nics = findNICs(); 0091 endResetModel(); 0092 } 0093 0094 // Convenience wrapper around sa_len being available or not. 0095 static int getNameInfo(struct sockaddr *addr, struct ifaddrs *ifa, HostNameArray &hostOut) 0096 { 0097 hostOut.fill(0); 0098 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 0099 return getnameinfo(addr, ifa->ifa_addr->sa_len, hostOut.data(), hostOut.size(), nullptr, 0, NI_NUMERICHOST); 0100 #else 0101 return getnameinfo(addr, 0102 (ifa->ifa_addr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), 0103 hostOut.data(), 0104 hostOut.size(), 0105 nullptr, 0106 0, 0107 NI_NUMERICHOST); 0108 #endif 0109 } 0110 0111 QList<NetworkModel::MyNIC *> findNICs() 0112 { 0113 QList<NetworkModel::MyNIC *> nl; 0114 0115 struct ifaddrs *ifap = nullptr; 0116 if (getifaddrs(&ifap) != 0) { 0117 return nl; 0118 } 0119 0120 for (auto *ifa = ifap; ifa; ifa = ifa->ifa_next) { 0121 if (!ifa->ifa_addr) { 0122 qDebug() << "stumbled over an interface without ifa_addr. You may wish to file a bug against kinfocenter" << ifa->ifa_name << ifa->ifa_flags; 0123 continue; 0124 } 0125 0126 switch (ifa->ifa_addr->sa_family) { 0127 case AF_INET6: 0128 case AF_INET: { 0129 auto tmp = new NetworkModel::MyNIC; 0130 tmp->name = ifa->ifa_name; 0131 0132 HostNameArray hostBuffer; 0133 0134 getNameInfo(ifa->ifa_addr, ifa, hostBuffer); 0135 tmp->addr = hostBuffer.data(); 0136 0137 if (ifa->ifa_netmask != nullptr) { 0138 getNameInfo(ifa->ifa_netmask, ifa, hostBuffer); 0139 tmp->netmask = hostBuffer.data(); 0140 } 0141 0142 tmp->state = (ifa->ifa_flags & IFF_UP) ? true : false; 0143 tmp->type = flags_tos(ifa->ifa_flags); 0144 0145 nl.append(tmp); 0146 break; 0147 } 0148 default: 0149 break; 0150 } 0151 } 0152 0153 freeifaddrs(ifap); 0154 return nl; 0155 } 0156 0157 QString flags_tos(unsigned int flags) 0158 { 0159 QString tmp; 0160 if (flags & IFF_POINTOPOINT) { 0161 tmp += i18nc("@item:intable Network type", "Point to Point"); 0162 } 0163 0164 if (flags & IFF_BROADCAST) { 0165 if (tmp.length()) { 0166 tmp += QLatin1String(", "); 0167 } 0168 tmp += i18nc("@item:intable Network type", "Broadcast"); 0169 } 0170 0171 if (flags & IFF_MULTICAST) { 0172 if (tmp.length()) { 0173 tmp += QLatin1String(", "); 0174 } 0175 tmp += i18nc("@item:intable Network type", "Multicast"); 0176 } 0177 0178 if (flags & IFF_LOOPBACK) { 0179 if (tmp.length()) { 0180 tmp += QLatin1String(", "); 0181 } 0182 tmp += i18nc("@item:intable Network type", "Loopback"); 0183 } 0184 return tmp; 0185 }