diff --git a/include/hwaddress.h b/include/hwaddress.h index caecefe..18efff3 100644 --- a/include/hwaddress.h +++ b/include/hwaddress.h @@ -79,6 +79,10 @@ public: return !(*this == rhs); } + const size_t size() const { + return address_size; + } + friend std::ostream &operator<<(std::ostream &os, const HWAddress &addr) { std::transform( addr.buffer, diff --git a/include/ipaddress.h b/include/ipaddress.h index 81a9052..a45a694 100644 --- a/include/ipaddress.h +++ b/include/ipaddress.h @@ -38,6 +38,11 @@ namespace Tins { operator uint32_t() const; operator std::string() const; + bool operator==(const std::string &rhs) const; + bool operator!=(const std::string &rhs) const { + return !(*this == rhs); + } + friend std::ostream &operator<<(std::ostream &output, const IPv4Address &addr) { return output << (std::string)addr; } diff --git a/include/network_interface.h b/include/network_interface.h index 2a6e89c..ceda418 100644 --- a/include/network_interface.h +++ b/include/network_interface.h @@ -25,26 +25,89 @@ #include #include #include "hwaddress.h" +#include "ipaddress.h" namespace Tins { +/** + * \class NetworkInterface + * \brief Abstraction of a network interface + */ class NetworkInterface { public: + /** + * \brief The type used to store the interface's identifier. + */ typedef uint32_t id_type; - typedef HWAddress<6> address_type; - - NetworkInterface(const std::string &name); - NetworkInterface(id_type id); + /** + * \brief The type of this interface's address. + */ + typedef HWAddress<6> address_type; + + /** + * \brief Struct that holds an interface's addresses. + */ + struct Info { + IPv4Address ip_addr, netmask, bcast_addr; + address_type hw_addr; + }; + + /** + * \brief Constructor from std::string. + * + * \param name The name of the interface this object will abstract. + */ + NetworkInterface(const std::string &name); + + /** + * \brief Constructs a NetworkInterface from an ip address. + * + * This abstracted interface will be the one that would be the gateway + * when sending a packet to the given ip. + * + * \param ip The ip address being looked up. + */ + NetworkInterface(IPv4Address ip); + + /** + * \brief Getter for this interface's identifier. + * + * \return id_type containing the identifier. + */ id_type id() const { return iface_id; } - address_type address(); + /** + * \brief Retrieves this interface's name. + * + * \return std::string containing this interface's name. + */ + std::string name() const; + /** + * \brief Retrieve this interface's addresses. + * + * This method iterates through all the interface's until the + * correct one is found. Therefore it's O(N), being N the amount + * of interfaces in the system. + */ + Info addresses() const; + + /** + * \brief Compares this interface for equality. + * + * \param rhs The interface being compared. + */ bool operator==(const NetworkInterface &rhs) const { return iface_id == rhs.iface_id; } + /** + * \brief Compares this interface for inequality. + * + * \param rhs The interface being compared. + */ bool operator!=(const NetworkInterface &rhs) const { return !(*this == rhs); } diff --git a/include/utils.h b/include/utils.h index 963570a..da7ee37 100644 --- a/include/utils.h +++ b/include/utils.h @@ -291,7 +291,7 @@ namespace Tins { struct ifaddrs *if_it = 0; getifaddrs(&ifaddrs); for(if_it = ifaddrs; if_it; if_it = if_it->ifa_next) { - if(!functor(if_it)) + if(functor(if_it)) break; } if(ifaddrs) diff --git a/src/ipaddress.cpp b/src/ipaddress.cpp index 5c1420c..4e20895 100644 --- a/src/ipaddress.cpp +++ b/src/ipaddress.cpp @@ -24,30 +24,35 @@ using std::string; -Tins::IPv4Address::IPv4Address(uint32_t ip) : ip_addr(ip) { +namespace Tins{ +IPv4Address::IPv4Address(uint32_t ip) : ip_addr(ip) { } -Tins::IPv4Address::IPv4Address(const std::string &ip) : +IPv4Address::IPv4Address(const std::string &ip) : ip_addr(Utils::ip_to_int(ip)) { } -Tins::IPv4Address &Tins::IPv4Address::operator=(uint32_t ip) { +IPv4Address &IPv4Address::operator=(uint32_t ip) { ip_addr = ip; return *this; } -Tins::IPv4Address &Tins::IPv4Address::operator=(const string &ip) { +IPv4Address &Tins::IPv4Address::operator=(const string &ip) { ip_addr = Utils::ip_to_int(ip); return *this; } -Tins::IPv4Address::operator uint32_t() const { +IPv4Address::operator uint32_t() const { return Utils::net_to_host_l(ip_addr); } -Tins::IPv4Address::operator std::string() const { +IPv4Address::operator std::string() const { return Utils::ip_to_string(ip_addr); } +bool IPv4Address::operator==(const std::string &rhs) const { + return ip_addr == Utils::ip_to_int(rhs); +} +} diff --git a/src/network_interface.cpp b/src/network_interface.cpp index de43429..cd1cb34 100644 --- a/src/network_interface.cpp +++ b/src/network_interface.cpp @@ -20,6 +20,8 @@ */ #include +#include +#include #ifndef WIN32 #include #include @@ -28,24 +30,35 @@ #include "utils.h" /** \cond */ -template -struct HWAddressCollector { - Address *result; +struct InterfaceInfoCollector { + typedef Tins::NetworkInterface::Info info_type; + info_type *info; int iface_id; + const char* iface_name; bool found; - HWAddressCollector(Tins::HWAddress<6> *res, int id) - : result(res), iface_id(id), found(false){ } + InterfaceInfoCollector(info_type *res, int id, const char* if_name) + : info(res), iface_id(id), iface_name(if_name), found(false) { } bool operator() (struct ifaddrs *addr) { + using Tins::Utils::net_to_host_l; const struct sockaddr_ll* addr_ptr = ((struct sockaddr_ll*)addr->ifa_addr); - if(!found && addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) { - *result = addr_ptr->sll_addr; + + if(addr->ifa_addr->sa_family == AF_PACKET && addr_ptr->sll_ifindex == iface_id) + info->hw_addr = addr_ptr->sll_addr; + else if(addr->ifa_addr->sa_family == AF_INET && !std::strcmp(addr->ifa_name, iface_name)) { + info->ip_addr = net_to_host_l(((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr); + info->netmask = net_to_host_l(((struct sockaddr_in *)addr->ifa_netmask)->sin_addr.s_addr); + if((addr->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT))) + info->bcast_addr = net_to_host_l(((struct sockaddr_in *)addr->ifa_ifu.ifu_broadaddr)->sin_addr.s_addr); + else + info->bcast_addr = 0; found = true; } return found; } }; +/** \endcond */ namespace Tins { NetworkInterface::NetworkInterface(const std::string &name) { @@ -54,18 +67,41 @@ NetworkInterface::NetworkInterface(const std::string &name) { throw std::runtime_error("Invalid interface error"); } -NetworkInterface::NetworkInterface(id_type id) -: iface_id(id) { +NetworkInterface::NetworkInterface(IPv4Address ip) : iface_id(0) { + typedef std::vector entries_type; + if(ip == "127.0.0.1") + iface_id = if_nametoindex("lo"); + else { + entries_type entries; + uint32_t ip_int = ip; + route_entries(std::back_inserter(entries)); + for(entries_type::const_iterator it(entries.begin()); it != entries.end(); ++it) { + if((ip_int & it->mask) == it->destination) { + iface_id = if_nametoindex(it->interface.c_str()); + break; + } + } + if(!iface_id) + throw std::runtime_error("Error looking up interface"); + } } -NetworkInterface::address_type NetworkInterface::address() { - address_type addr; - ::HWAddressCollector collector(&addr, iface_id); +std::string NetworkInterface::name() const { + char iface_name[IF_NAMESIZE]; + if(!if_indextoname(iface_id, iface_name)) + throw std::runtime_error("Error fetching this interface's name"); + return iface_name; +} + +NetworkInterface::Info NetworkInterface::addresses() const { + const std::string &iface_name = name(); + Info info; + InterfaceInfoCollector collector(&info, iface_id, iface_name.c_str()); Utils::generic_iface_loop(collector); if(!collector.found) throw std::runtime_error("Error looking up interface address"); - return addr; + return info; } } diff --git a/tests/src/network_interface.cpp b/tests/src/network_interface.cpp new file mode 100644 index 0000000..6a667ba --- /dev/null +++ b/tests/src/network_interface.cpp @@ -0,0 +1,58 @@ +#include +#include +#include "network_interface.h" +#include "utils.h" + +using namespace Tins; + +class NetworkInterfaceTest : public ::testing::Test { +public: + static const std::string iface_name, iface_addr; +}; + +const std::string NetworkInterfaceTest::iface_name("lo"), + NetworkInterfaceTest::iface_addr(""); + + +TEST_F(NetworkInterfaceTest, ConstructorFromString) { + // just test this doesn't throw + NetworkInterface iface(iface_name); + + try { + NetworkInterface iface("ishallnotexist"); + ASSERT_TRUE(false); + } + catch(...) { + + } +} + +TEST_F(NetworkInterfaceTest, ConstructorFromIp) { + NetworkInterface iface(IPv4Address("127.0.0.1")); + EXPECT_EQ(iface.name(), "lo"); +} + +TEST_F(NetworkInterfaceTest, Id) { + NetworkInterface iface(iface_name); + EXPECT_TRUE(iface.id() != 0); +} + +TEST_F(NetworkInterfaceTest, Info) { + NetworkInterface iface(iface_name); + NetworkInterface::Info info(iface.addresses()); + // assuming it's like this + EXPECT_EQ(info.ip_addr, "127.0.0.1"); + EXPECT_EQ(info.netmask, "255.0.0.0"); +} + +TEST_F(NetworkInterfaceTest, EqualsOperator) { + NetworkInterface iface1(iface_name), iface2(iface_name); + EXPECT_EQ(iface1, iface2); +} + +TEST_F(NetworkInterfaceTest, DistinctOperator) { + NetworkInterface iface1(iface_name), iface2("eth0"); + EXPECT_NE(iface1, iface2); +} + +