From 8a52a45dd1cf8d0ddb38b5da2d961c5a69f95fdc Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 15 Sep 2013 18:41:25 -0400 Subject: [PATCH] add option to set interface state up/down, not working yet (returns "Object busy" from netlink) --- interface.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++ interface.h | 3 ++ tui/menu.cpp | 51 +++++++++++++++++++--- 3 files changed, 163 insertions(+), 6 deletions(-) diff --git a/interface.cpp b/interface.cpp index 7e6eb00..26fed85 100644 --- a/interface.cpp +++ b/interface.cpp @@ -39,6 +39,84 @@ m_index(-1) m_index = Utils::interfaceIndex(interface); } +bool Interface::setLinkUp(QString &error) { + struct rtnl_link *link, *link_orig = NULL; + struct nl_sock *sock = NULL; + QByteArray interfaceArray = m_interface.toLatin1(); + const char *interface = interfaceArray.constData(); + + if((sock = Utils::connect())) { + rtnl_link_get_kernel(sock, 0, interface, &link_orig); + + if(rtnl_link_get_kernel(sock, 0, interface, &link) < 0) { + std::cerr << "error looking up interface" << std::endl; + nl_socket_free(sock); + }else{ + unsigned int flags = rtnl_link_get_flags(link); + int err = 0; + + flags |= IFF_UP; + + rtnl_link_set_flags(link, flags); + + if((err = rtnl_link_change(sock, link_orig, link, 0)) < 0) { + error = nl_geterror(err); + rtnl_link_put(link); + rtnl_link_put(link_orig); + nl_socket_free(sock); + return false; + } + + rtnl_link_put(link); + rtnl_link_put(link_orig); + nl_socket_free(sock); + + return true; + } + } + + return false; +} + +bool Interface::setLinkDown(QString &error) { + struct rtnl_link *link, *link_orig = NULL; + struct nl_sock *sock = NULL; + QByteArray interfaceArray = m_interface.toLatin1(); + const char *interface = interfaceArray.constData(); + + if((sock = Utils::connect())) { + rtnl_link_get_kernel(sock, 0, interface, &link_orig); + + if(rtnl_link_get_kernel(sock, 0, interface, &link) < 0) { + std::cerr << "error looking up interface" << std::endl; + nl_socket_free(sock); + }else{ + unsigned int flags = rtnl_link_get_flags(link); + int err = 0; + + flags &= ~IFF_UP; + + rtnl_link_set_flags(link, flags); + + if((err = rtnl_link_change(sock, link_orig, link, 0)) < 0) { + error = nl_geterror(err); + rtnl_link_put(link); + rtnl_link_put(link_orig); + nl_socket_free(sock); + return false; + } + + rtnl_link_put(link); + rtnl_link_put(link_orig); + nl_socket_free(sock); + + return true; + } + } + + return false; +} + /*! Add an IP address to the interface using the CIDR notation, e.g. 192.168.1.1/24. Requires that the CAP_NET_ADMIN capability be set on the application binary, or run as root (\a not \a recommended). Returns 0 on success, 1 on error. */ @@ -214,6 +292,43 @@ int Interface::deleteAddress(QString addressStr) const { return 0; } +/*! + Returns true if the interface is administratively up, otherwise false if it is administratively down or if there was an error retrieving the status information. If there was an error, *ok will be set to false, otherwise it will be true. +*/ +bool Interface::hasAdminLink(bool *ok) { + struct rtnl_link *link = NULL; + struct nl_sock *sock = NULL; + QByteArray interfaceArray = m_interface.toLatin1(); + const char *interface = interfaceArray.constData(); + bool carrier = false; + + if((sock = Utils::connect())) { + if(rtnl_link_get_kernel(sock, 0, interface, &link) < 0) { + std::cerr << "error looking up interface" << std::endl; + nl_socket_free(sock); + }else{ + unsigned int flags = rtnl_link_get_flags(link); + + carrier = (flags & IFF_UP) == IFF_UP; + + rtnl_link_put(link); + nl_socket_free(sock); + + if(ok != NULL) { + *ok = true; + } + + return carrier; + } + } + + if(ok != NULL) { + *ok = false; + } + + return false; +} + /*! Returns true if the interface is up and running (link-layer is up), and false if the link/interface is down, or if there was an error retrieving the status information. If there was an error, *ok will be set to false, otherwise it will be true. */ diff --git a/interface.h b/interface.h index de9f463..af8b8d5 100644 --- a/interface.h +++ b/interface.h @@ -12,6 +12,9 @@ public: static QStringList list(); QStringList addresses() const; bool hasCarrier(bool *ok = 0); + bool hasAdminLink(bool *ok = 0); + bool setLinkUp(QString &error); + bool setLinkDown(QString &error); int addAddress(QString address) const; int deleteAddress(QString address) const; const QString& name() const; diff --git a/tui/menu.cpp b/tui/menu.cpp index 896c259..60c39ed 100644 --- a/tui/menu.cpp +++ b/tui/menu.cpp @@ -265,6 +265,15 @@ void Menu::interfaceMenu(WINDOW *window) { interface = QString::number(count) + ". " + interface; QByteArray interfaceArray = interface.toLatin1(); const char *interfaceStr = interfaceArray.constData(); + Interface interfaceObj(orig); + + if(interfaceObj.hasCarrier()) { + green(window); + }else if(interfaceObj.hasAdminLink()) { + cyan(window); + }else{ + red(window); + } mvwaddstr(window, y, 2, interfaceStr); @@ -619,9 +628,11 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { magenta(window); mvwaddstr(window, y + 3, 2, "a. Add IP address"); mvwaddstr(window, y + 4, 2, "d. Delete IP address"); - mvwaddstr(window, y + 5, 2, "q. Quit"); + mvwaddstr(window, y + 5, 2, "+. Set link up"); + mvwaddstr(window, y + 6, 2, "-. Set link down"); + mvwaddstr(window, y + 7, 2, "q. Quit"); - mvwaddstr(window, y + 7, 2, "Enter selection: "); + mvwaddstr(window, y + 9, 2, "Enter selection: "); wrefresh(window); char c = getch(); @@ -633,7 +644,7 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { // no-op, just quit }else if(c == 'a') { wdeleteln(window); - mvwaddstr(window, y + 7, 2, "Enter IP address to add: "); + mvwaddstr(window, y + 9, 2, "Enter IP address to add: "); wrefresh(window); char ipToAdd[19] = {0}; @@ -659,7 +670,7 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { QByteArray arr = confirm.toLatin1(); const char *confirmStr = arr.constData(); - mvwaddstr(window, y + 7, 2, confirmStr); + mvwaddstr(window, y + 9, 2, confirmStr); wrefresh(window); c = getch(); @@ -677,7 +688,7 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { } }else if(c == 'd') { wdeleteln(window); - mvwaddstr(window, y + 7, 2, "Enter number of IP address to delete: "); + mvwaddstr(window, y + 9, 2, "Enter number of IP address to delete: "); wrefresh(window); char ipToDelete = getch(); @@ -700,7 +711,7 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { QByteArray arr = confirm.toLatin1(); const char *confirmStr = arr.constData(); - mvwaddstr(window, y + 7, 2, confirmStr); + mvwaddstr(window, y + 9, 2, confirmStr); wrefresh(window); c = getch(); @@ -716,6 +727,34 @@ void Menu::interfaceSelect(WINDOW *window, QString interface) { }else{ interfaceSelect(window, interface); } + }else if(c == '+') { + QString error; + + if(!obj.setLinkUp(error)) { + QString err = QString("Could not change link state: ") + error; + QByteArray arr = err.toLatin1(); + const char *errorString = arr.constData(); + + msgbox(errorString); + }else{ + msgbox("Link state set to UP."); + } + + interfaceSelect(window, interface); + }else if(c == '-') { + QString error; + + if(!obj.setLinkDown(error)) { + QString err = QString("Could not change link state: ") + error; + QByteArray arr = err.toLatin1(); + const char *errorString = arr.constData(); + + msgbox(errorString); + }else{ + msgbox("Link state set to DOWN."); + } + + interfaceSelect(window, interface); }else{ interfaceSelect(window, interface); }