From 74249cefb231986473253c1c6a7acbbb86f92b2f Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Tue, 8 Dec 2015 15:23:18 -0500 Subject: [PATCH] Copy over the new sysadm library/binary from the pcbsd/pcbsd repo into it's own repo. --- src/binary/binary.pro | 19 ++ src/binary/main.cpp | 33 ++++ src/library/NetDevice.cpp | 311 +++++++++++++++++++++++++++++++++ src/library/library.pro | 27 +++ src/library/sysadm-general.cpp | 119 +++++++++++++ src/library/sysadm-general.h | 37 ++++ src/library/sysadm-global.h | 36 ++++ src/library/sysadm-network.cpp | 125 +++++++++++++ src/library/sysadm-network.h | 97 ++++++++++ src/sysadm.pro | 8 + 10 files changed, 812 insertions(+) create mode 100644 src/binary/binary.pro create mode 100644 src/binary/main.cpp create mode 100644 src/library/NetDevice.cpp create mode 100644 src/library/library.pro create mode 100644 src/library/sysadm-general.cpp create mode 100644 src/library/sysadm-general.h create mode 100644 src/library/sysadm-global.h create mode 100644 src/library/sysadm-network.cpp create mode 100644 src/library/sysadm-network.h create mode 100644 src/sysadm.pro diff --git a/src/binary/binary.pro b/src/binary/binary.pro new file mode 100644 index 0000000..cfac6f8 --- /dev/null +++ b/src/binary/binary.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +LANGUAGE = C++ + +CONFIG += qt warn_on release +QT = core + +SOURCES += main.cpp + +LIBS = -L../library -L/usr/lib -L/usr/local/lib -lsysadm +INCLUDEPATH += ../library /usr/include /usr/local/include + +TARGET=sysadm +target.path=/usr/local/bin + + +INSTALLS += target + + +QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib diff --git a/src/binary/main.cpp b/src/binary/main.cpp new file mode 100644 index 0000000..f23f3b7 --- /dev/null +++ b/src/binary/main.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include + +int main( int argc, char ** argv ) +{ + //Run a simple test of all the sysadm backend functions + QStringList devs = sysadm::NetDevice::listNetDevices(); + qDebug() <<"Devices:" << devs; + for(int i=0; iifa_name, IFNAMSIZ); + if (result.contains(ifName) == 0) result += ifName; + ifap = ifap->ifa_next; + } + //Close the + freeifaddrs(ifap); + return result; +} + +//===================== +// CLASS FUNCTIONS +//===================== +//Get the name of the device (taking off any numbers) +QString NetDevice::devName(){ + uint pos = name.indexOf(QRegExp("[0-9]+$")); + QString result = name; + result.truncate(pos); + return result; +} + +//Return just the number of the device (removing the name) +uint NetDevice::devNum(){ + uint pos = name.indexOf(QRegExp("[0-9]+$")); + return name.mid(pos).toInt(); +} + +//Fetch the IP and return it as a QString +QString NetDevice::ipAsString(){ + struct ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(PF_INET, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFADDR, &ifr); + struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr; + + return QString(inet_ntoa(in)); +} + +//Fetch the IPv6 and return it as a QString +QString NetDevice::ipv6AsString(){ + //Note: New on 6/24/15 - still needs testing + struct ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(PF_INET6, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFADDR, &ifr); + struct in6_addr in = ((sockaddr_in6 *) &ifr.ifr_addr)->sin6_addr; + char straddr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &in, straddr, sizeof(straddr)); + return QString(straddr); +} + +//Fetch the netmask and return it as a QString +QString NetDevice::netmaskAsString(){ + struct ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(PF_INET, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFNETMASK, &ifr); + struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr; + + return QString(inet_ntoa(in)); +} + +//Returns the description string for the device +QString NetDevice::desc(){ + return General::sysctl("dev." + devName() + "." + QString::number(devNum()) + ".%desc"); +} + +//Fetch the mac address as a QString +QString NetDevice::macAsString(){ + int mib[6]; + size_t len; + char *buf; + struct sockaddr_dl *sdl; + char *ptr; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(name.toLocal8Bit()); + + //First find the size of the return, so we can adjust buf accordingly + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = (char *) malloc(len); + sysctl(mib, 6, buf, &len, NULL, 0); + + sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1); + ptr = (char *) LLADDR(sdl); + + QString mac; + for (uint i=0; i < 6; i++){ + mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0'); + if(i<5){ mac += ":"; } + } + return mac; +} + +//Get the status of the device (active, associated, etc...) +QString NetDevice::mediaStatusAsString(){ + struct ifmediareq ifm; + memset(&ifm, 0, sizeof(struct ifmediareq)); + + strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(AF_INET, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFMEDIA, &ifm); + QString status; + + switch (IFM_TYPE(ifm.ifm_active)){ + case IFM_FDDI: + case IFM_TOKEN: + if (ifm.ifm_status & IFM_ACTIVE) status = "inserted"; + else status = "no ring"; + break; + case IFM_IEEE80211: + if (ifm.ifm_status & IFM_ACTIVE) status = "associated"; + else status = "no carrier"; + break; + default: + if (ifm.ifm_status & IFM_ACTIVE) status = "active"; + else status = "no carrier"; + } + return status; +} + +QString NetDevice::gatewayAsString(){ + QString info = General::RunCommand("nice netstat -n -r").split("\n").filter(name).filter("default").join("\n"); + if(info.isEmpty()){ return ""; } + //Pull the gateway out of the first line ( ) + info = info.replace("\t"," ").section("\n",0,0).simplified(); //ensure proper parsing + return info.section(" ",1,1); +} + +//Check if a device is wireless or not +bool NetDevice::isWireless(){ + struct ifmediareq ifm; + memset(&ifm, 0, sizeof(struct ifmediareq)); + + strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(AF_INET, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFMEDIA, &ifm); + + return IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211; +} + +//Get the parent device (if this is a wireless wlan) +QString NetDevice::getWifiParent(){ + if(!name.contains("wlan")){ return ""; } + return General::sysctl("net.wlan." + QString::number(this->devNum()) + ".%parent"); +} + +//See if the device is setup to use DHCP +bool NetDevice::usesDHCP(){ + //The system does not keep track of how the device's address was assigned + // so the closest we can get to this is to see if the system is setup to use + // DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15) + return !Network::readRcConf().filter(name).filter("DHCP").isEmpty(); +} + +//See if the device is currently in use +bool NetDevice::isUp(){ + struct ifreq ifr; + memset(&ifr, 0, sizeof(struct ifreq)); + + strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); + int s = socket(AF_INET, SOCK_DGRAM, 0); + + ioctl(s, SIOCGIFFLAGS, &ifr); + + return (ifr.ifr_flags & IFF_UP) ? 1 : 0; +} + +//Determine the number of packets received by the device +long NetDevice::packetsRx(){ + int mib[6]; + size_t len; + char *buf; + struct if_msghdr *ifm; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(name.toLocal8Bit()); + + //First find the size of the return, so we can adjust buf accordingly + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = (char *) malloc(len); + sysctl(mib, 6, buf, &len, NULL, 0); + + ifm = (if_msghdr *) buf; + + return ifm->ifm_data.ifi_ipackets; +} + +//Determine the number of packets transmitted by the device +long NetDevice::packetsTx(){ + int mib[6]; + size_t len; + char *buf; + struct if_msghdr *ifm; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(name.toLocal8Bit()); + + //First find the size of the return, so we can adjust buf accordingly + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = (char *) malloc(len); + sysctl(mib, 6, buf, &len, NULL, 0); + + ifm = (if_msghdr *) buf; + + return ifm->ifm_data.ifi_opackets; +} + +//Determine the number of errors received +long NetDevice::errorsRx(){ + int mib[6]; + size_t len; + char *buf; + struct if_msghdr *ifm; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(name.toLocal8Bit()); + + //First find the size of the return, so we can adjust buf accordingly + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = (char *) malloc(len); + sysctl(mib, 6, buf, &len, NULL, 0); + + ifm = (if_msghdr *) buf; + + return ifm->ifm_data.ifi_ierrors; +} + +//Determine the number of errors transmitted +long NetDevice::errorsTx(){ + int mib[6]; + size_t len; + char *buf; + struct if_msghdr *ifm; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = AF_LINK; + mib[4] = NET_RT_IFLIST; + mib[5] = if_nametoindex(name.toLocal8Bit()); + + //First find the size of the return, so we can adjust buf accordingly + sysctl(mib, 6, NULL, &len, NULL, 0); + buf = (char *) malloc(len); + sysctl(mib, 6, buf, &len, NULL, 0); + + ifm = (if_msghdr *) buf; + + return ifm->ifm_data.ifi_oerrors; +} + +//========================= +// SETTING FUNCTIONS (requires root) +//========================= +void NetDevice::setUp(bool up){ + //This only sets it up/down for the current session - does not change usage on next boot + General::RunCommand("ifconfig "+name+" "+ (up ? "up": "down") ); +} diff --git a/src/library/library.pro b/src/library/library.pro new file mode 100644 index 0000000..e99231f --- /dev/null +++ b/src/library/library.pro @@ -0,0 +1,27 @@ + +QT += core network + +TARGET=sysadm +target.path = /usr/local/lib + +DESTDIR= $$_PRO_FILE_PWD_ + +TEMPLATE = lib +LANGUAGE = C++ +VERSION = 1.0.0 + +HEADERS += sysadm-global.h \ + sysadm-general.h \ + sysadm-network.h + + +SOURCES += sysadm-general.cpp \ + sysadm-network.cpp \ + NetDevice.cpp + +include.path=/usr/local/include/ +include.files=sysadm-*.h + +INSTALLS += target include + +QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib diff --git a/src/library/sysadm-general.cpp b/src/library/sysadm-general.cpp new file mode 100644 index 0000000..9e0cb40 --- /dev/null +++ b/src/library/sysadm-general.cpp @@ -0,0 +1,119 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "sysadm-general.h" +//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h + +#include "sysadm-global.h" + +using namespace sysadm; +//================= +// RunCommand() variations +//================= +//Note: environment changes should be listed as such: = + +//Return CLI output (and success/failure) +QString General::RunCommand(bool &success, QString command, QStringList arguments, QString workdir, QStringList env){ + QProcess proc; + proc.setProcessChannelMode(QProcess::MergedChannels); //need output + //First setup the process environment as necessary + QProcessEnvironment PE = QProcessEnvironment::systemEnvironment(); + if(!env.isEmpty()){ + for(int i=0; i=] + // - Both success/log of output + static QString RunCommand(bool &success, QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() ); + // - Log output only + static QString RunCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() ); + // - success output only + static bool RunQuickCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() ); + + //File Access Functions + static QStringList readTextFile(QString filename); + static bool writeTextFile(QString filename, QStringList contents, bool overwrite = true); + + //Retrieve a text-based sysctl + static QString sysctl(QString var); + //Retrieve a number-based sysctl + static long long sysctlAsInt(QString var); +}; + +} //end of pcbsd namespace + +#endif \ No newline at end of file diff --git a/src/library/sysadm-global.h b/src/library/sysadm-global.h new file mode 100644 index 0000000..f9700d1 --- /dev/null +++ b/src/library/sysadm-global.h @@ -0,0 +1,36 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef __PCBSD_LIB_UTILS_GENERAL_INCLUDES_H +#define __PCBSD_LIB_UTILS_GENERAL_INCLUDES_H + +//Qt Includes +#include +#include +#include +#include +#include +#include +#include +#include + +//FreeBSD Includes +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include //from "man getnetent" (network entries) + +#endif diff --git a/src/library/sysadm-network.cpp b/src/library/sysadm-network.cpp new file mode 100644 index 0000000..0ba705e --- /dev/null +++ b/src/library/sysadm-network.cpp @@ -0,0 +1,125 @@ +//=========================================== +// PC-BSD source code +// Copyright (c) 2015, PC-BSD Software/iXsystems +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "sysadm-network.h" +//PLEASE: Keep the functions in the same order as listed in pcbsd-network.h +#include "sysadm-general.h" + +using namespace sysadm; +//===================== +// NETWORK FUNCTIONS +//===================== +QList Network::listNetworkEntries(){ + QList out; + netent *entry = getnetent(); + while(entry!=0){ + //Copy over this data into the output structure + NetworkEntry tmp; + tmp.name = QString::fromLocal8Bit(entry->n_name); + for(int i=0; entry->n_aliases[i] != 0; i++){ + tmp.aliases << QString::fromLocal8Bit(entry->n_aliases[i]); + } + tmp.netnum = entry->n_net; + out << tmp; + //Now load the next entry + entry = getnetent(); + } + endnetent(); //make sure to close the file since we are finished reading it + return out; +} + +//--------------------------------------- +QStringList Network::readRcConf(){ + static QStringList contents = QStringList(); + static QDateTime lastread; + if(!lastread.isValid() || contents.isEmpty() || (QFileInfo("/etc/rc.conf").lastModified()> lastread) ){ + lastread = QDateTime::currentDateTime(); + contents = General::readTextFile("/etc/rc.conf"); + } + return contents; +} + +//--------------------------------------- +NetDevSettings Network::deviceRCSettings(QString dev){ + QStringList info = Network::readRcConf().filter(dev); + NetDevSettings set; + if(info.isEmpty()){ return set; } //no settings + set.device = dev; + set.wifihost = false; + for(int i=0; i wlan device) + //Wifi + QString wifiCountry, wifiSSID, wifiBSSID, wifichannel; + bool wifihost; + //General + QString etherMac; + //NOTE: All the "static" variables are only used for rc.conf settings + // For the current IP/IPv6 information use the "NetDevice" class below + QString staticIPv4, staticNetmask, staticIPv6; //assumes DHCP if none are set + QString staticGateway; +}; + +//General data class for network devices +// Note: Sources in NetDevice.cpp +class NetDevice{ +private: + QString name; +public: + NetDevice(QString devName){ name = devName; } + QString device(){ return name; } //full device name (wlan0) + QString devName(); //name only (wlan) + uint devNum(); //number only (0) + QString ipAsString(); + QString ipv6AsString(); + QString netmaskAsString(); + QString desc(); + QString macAsString(); + //QString mediaTypeAsString(); + QString mediaStatusAsString(); + QString gatewayAsString(); + bool isWireless(); + QString getWifiParent(); + bool usesDHCP(); + bool isUp(); + long packetsRx(); + long packetsTx(); + long errorsRx(); + long errorsTx(); + + //Setting Functions (to make changes - requires root) + void setUp(bool up); //Turn device on/off (temporary - not saved globally) + + //Generic listing of devices + static QStringList listNetDevices(); //probe the system for all network devices +}; + +//General data structure for wifi access points (local or available) +struct NetWifi{ + NetCrypt encryption; +}; + + +//The general-purpose class that any user/app can utilitize +class Network{ +public: + static QList listNetworkEntries(); + static QStringList readRcConf(); //use this when reading /etc/rc.conf for network stuff - prevents opening the file repeatedly + static NetDevSettings deviceRCSettings(QString dev); //settings in rc.conf (bootup) + static NetDevSettings deviceIfconfigSettings(QString dev); //settings currently running +}; + +//The class that requires overarching root permissions (usually for changes to system) +class NetworkRoot{ +public: + static bool saveNetworkEntry(NetworkEntry); //**Not implemented yet** + static bool saveRCSettings(NetDevSettings); //rc.conf settings (bootup) + static bool setIfconfigSettings(NetDevSettings); //ifconfig settings (temporary session) +}; + +} //end of pcbsd namespace + +#endif \ No newline at end of file diff --git a/src/sysadm.pro b/src/sysadm.pro new file mode 100644 index 0000000..ff8a62c --- /dev/null +++ b/src/sysadm.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +CONFIG += recursive + +SUBDIRS+= library binary + +#Make sure to list the library as a requirement for the others (for parallellized builds) +binary.depends = library +