diff --git a/src/library/library.pro b/src/library/library.pro index e599734..769fca9 100644 --- a/src/library/library.pro +++ b/src/library/library.pro @@ -1,4 +1,4 @@ - +CONFIG += c++11 QT += core network TARGET=sysadm diff --git a/src/library/sysadm-firewall.cpp b/src/library/sysadm-firewall.cpp index 3efd387..6ef15bb 100644 --- a/src/library/sysadm-firewall.cpp +++ b/src/library/sysadm-firewall.cpp @@ -1,10 +1,18 @@ +//=========================================== +// 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-firewall.h" #include +#include + using namespace sysadm; -PortInfo Firewall::LookUpPort(int portNumber, QString portType) +PortInfo Firewall::LookUpPort(int port, QString type) { //Make sure that the port is valid - if (portNumber < 0 || portNumber > 65535) + if (port < 0 || port > 65535) { PortInfo returnValue; returnValue.Port = -1; @@ -19,19 +27,19 @@ PortInfo Firewall::LookUpPort(int portNumber, QString portType) PortInfo returnValue; //the port number is valid so set it - returnValue.Port = portNumber; + returnValue.Port = port; //make sure that the portType is cased in lower to match the service file and //then store it in the returnValue, since there isn't a huge point in checking //the validitiy of the type since /etc/services lists more than udp/tcp - portType = portType.toLower(); - returnValue.PortType = portType; + type = type.toLower(); + returnValue.Type = type; //Check to see if it's a recommended port returnValue.Recommended = false; - for(int i = 0; i < recommendedPortsSize; i++) + for(int recommendedPort : recommendedPorts) { - if (portNumber == recommendedPorts[i]) + if (port == recommendedPort) { returnValue.Recommended = true; } @@ -40,12 +48,12 @@ PortInfo Firewall::LookUpPort(int portNumber, QString portType) //Check to see if the port number is listed. The format in the file // is portname/portType. ex.: 22/tcp - QStringList port = portStrings->filter(QString::number(portNumber) + "/" + portType); - if(port.size() > 0) + QStringList portList = portStrings->filter(QString::number(port) + "/" + type); + if(portList.size() > 0) { //grab the first one, there may be duplicates due to colliding ports in the /etc/services file //but those are listed after the declaration for what the port officially should be used for - QString line = port.at(0); + QString line = portList.at(0); //Split across spaces since it's whitespace delimited QStringList lineList = line.split(' '); @@ -70,9 +78,87 @@ PortInfo Firewall::LookUpPort(int portNumber, QString portType) } -Firewall::Firewall() +void Firewall::OpenPort(int port, QString type) { + openports.append(LookUpPort(port,type)); + SaveOpenPorts(); +} + +void Firewall::OpenPort(QVector ports) +{ + for(PortInfo port : ports) + { + openports.append(port); + } + SaveOpenPorts(); +} + +void Firewall::ClosePort(int port, QString type) +{ + openports.removeAll(LookUpPort(port,type)); + SaveOpenPorts(); +} + +void Firewall::ClosePort(QVector ports) +{ + for(PortInfo port : ports) + { + openports.removeAll(port); + } + SaveOpenPorts(); +} + +QVector Firewall::OpenPorts() +{ + return openports; + +} + +bool Firewall::IsRunning() +{ + QProcess proc; + proc.start("sysctl net.inet.ip.fw.enable"); + if(proc.waitForFinished() || proc.canReadLine()) + { + if (proc.canReadLine()) + { + QString line = proc.readLine(); + if(line.section(":",1,1).simplified().toInt() ==1) { return true; } + } + } + return false; +} + +void Firewall::Start() +{ + system("/etc/rc.d/ipfw start"); +} + +void Firewall::Stop() +{ + system("/etc/rc.d/ipfw stop"); +} + +void Firewall::Restart() +{ + system("/etc/rc.d/ipfw restart"); +} + +void Firewall::RestoreDefaults() +{ + //move the files out of the way + system("mv /etc/ipfw.rules /etc/ipfw.rules.previous"); + system("mv /etc/ipfw.openports /etc/ipfw.openports.previous"); + //refresh/restart the rules files + system("sh /usr/local/share/pcbsd/scripts/reset-firewall"); + + LoadOpenPorts(); +} + +Firewall::Firewall() +{ readServicesFile(); + LoadOpenPorts(); } Firewall::~Firewall() @@ -92,7 +178,7 @@ void Firewall::readServicesFile() { QString line = services->readLine(); //jump down past the comments - if(line[0] == '#') + if(line[0] == '#' || line.simplified().isEmpty()) continue; //remove all of the extraneous whitespace in the line @@ -103,4 +189,44 @@ void Firewall::readServicesFile() services->close(); delete services; } + +void Firewall::LoadOpenPorts() +{ + openports.clear(); + QFile file("/etc/ipfw.openports"); + if( file.open(QIODevice::ReadOnly) ){ + QTextStream in(&file); + while( !in.atEnd() ){ + QString line = in.readLine(); + if(line.startsWith("#") || line.simplified().isEmpty()){ continue; } + //File format: " " (nice and simple) + openports.append(LookUpPort(line.section(" ",1,1).toInt(),line.section(" ",0,0))); + } + file.close(); + } + //order them in ascending order by port then port type + std::sort(openports.begin(),openports.end()); +} + +void Firewall::SaveOpenPorts() +{ + //Convert to file format + std::sort(openports.begin(), openports.end()); //make sure they are still sorted by port + QStringList fileout; + for(PortInfo port : openports){ + fileout.append("#" + port.Keyword + ": " + port.Description + "\n" + + port.Type +" "+QString::number(port.Port)); + } + //Always make sure that the file always ends with a newline + if(!fileout.isEmpty()){ fileout << ""; } + //Save to file + QFile file("/etc/ipfw.openports"); + if( file.open(QIODevice::WriteOnly | QIODevice::Truncate) ){ + QTextStream out(&file); + out << fileout.join("\n"); + file.close(); + } + //Re-load/start rules (just in case - it is a smart script) + if(IsRunning()){ system("sh /usr/local/share/pcbsd/scripts/reset-firewall"); } +} diff --git a/src/library/sysadm-firewall.h b/src/library/sysadm-firewall.h index dbdccae..b6eb912 100644 --- a/src/library/sysadm-firewall.h +++ b/src/library/sysadm-firewall.h @@ -7,38 +7,117 @@ #ifndef PORTLOOKUP_H #define PORTLOOKUP_H #include +#include namespace sysadm { struct PortInfo{ int Port; - QString PortType; + QString Type; QString Keyword; QString Description; bool Recommended; + friend bool operator<(const PortInfo lhs, const PortInfo rhs){ + return std::tie(lhs.Port,lhs.Type) < std::tie(rhs.Port,rhs.Type); + } + friend bool operator>(const PortInfo lhs, const PortInfo rhs) + { return rhs < lhs;} + friend bool operator==(const PortInfo lhs, const PortInfo rhs) + { + return lhs.Port == rhs.Port && lhs.Type == rhs.Type; + } + friend bool operator !=(const PortInfo lhs, const PortInfo rhs) + { return !(lhs == rhs);} }; -const static int recommendedPorts[] = {22, 80}; -const static int recommendedPortsSize = 2; +const static QVector recommendedPorts = {22, 80}; class Firewall { public: + ///#section: port commands /** * @description Returns a structure containing information about the port * including its port type, keyword, description, and whether it's a * recommended port * - * @parameter portNumber a port number between 0 and 2^16 - 1 + * @param number a port number between 0 and 2^16 - 1 + * @param type specify whether the port is tdp, udp, etc * * @ErrorConditions Port Number is set to -1 and a description of the error is stored in the description variable */ - PortInfo LookUpPort(int portNumber, QString portType); + PortInfo LookUpPort(int number, QString type); + /** + * @brief Opens a port + * @param number a port number between 0 and 2^16 -1 + * @param type specify whether the port is tdp, udp, etc + */ + void OpenPort(int number, QString type); + + /** + * @brief Opens a set of ports + * @param ports a vector of ports to open + */ + void OpenPort(QVector ports); + + /** + * @brief ClosePort closes a port + * @param number a port number between 0 and 2^16 -1 + * @param type specify whether the port is tdp, udp, etc + */ + void ClosePort(int number, QString type); + + /** + * @brief ClosePort closes a set of ports + * @param ports a vector of ports to close + */ + void ClosePort(QVector ports); + + /** + * @brief finds a list of ports that are open gets the info about them + * and returns them + * @return a QVector of the open ports + */ + QVector OpenPorts(); + ///#endsection + + ///#section: firewall commands + /** + * @brief Checks to see if the firewall is running + * @return true if the firewall is running, false if not + */ + bool IsRunning(); + /** + * @brief Starts the firewall + */ + void Start(); + /** + * @brief Stops the firewall + */ + void Stop(); + /** + * @brief Restarts the firewall + */ + void Restart(); + + /** + * @brief Restores the Default Configuration + */ + void RestoreDefaults(); + ///#endsection + + ///#section: ctors dtors Firewall(); ~Firewall(); + ///#endsection private: void readServicesFile(); QStringList* portStrings; + + QVector openports; + + void LoadOpenPorts(); + void SaveOpenPorts(); }; } #endif // PORTLOOKUP_H