diff --git a/NetUtils.cpp b/NetUtils.cpp index f4046d8..ad45f29 100644 --- a/NetUtils.cpp +++ b/NetUtils.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,9 +20,11 @@ #include #include - #include "NetUtils.h" +#define TOIPV6(s) ((struct sockaddr_in6*)&s) +#define TOIPV4(s) (((struct sockaddr_in*)&s)) + bool CNetUtils::lookupV4(const std::string& hostname, sockaddr_storage& addr) { struct addrinfo hints; @@ -40,6 +43,13 @@ bool CNetUtils::lookupV6(const std::string& hostname, sockaddr_storage& addr) return lookup(hostname, addr, hints); } +bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr) +{ + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + return lookup(hostname, addr, hints); +} + bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints) { struct addrinfo *res; @@ -57,4 +67,58 @@ bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, stru ::freeaddrinfo(res); return true; -} \ No newline at end of file +} + +bool CNetUtils::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type) +{ + if (addr1.ss_family != addr2.ss_family) + return false; + + if (type == IMT_ADDRESS_AND_PORT) { + switch (addr1.ss_family) { + case AF_INET: + struct sockaddr_in *in_1, *in_2; + in_1 = (struct sockaddr_in*)&addr1; + in_2 = (struct sockaddr_in*)&addr2; + return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port); + case AF_INET6: + struct sockaddr_in6 *in6_1, *in6_2; + in6_1 = (struct sockaddr_in6*)&addr1; + in6_2 = (struct sockaddr_in6*)&addr2; + return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port); + default: + return false; + } + } else if (type == IMT_ADDRESS_ONLY) { + switch (addr1.ss_family) { + case AF_INET: + struct sockaddr_in *in_1, *in_2; + in_1 = (struct sockaddr_in*)&addr1; + in_2 = (struct sockaddr_in*)&addr2; + return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr; + case AF_INET6: + struct sockaddr_in6 *in6_1, *in6_2; + in6_1 = (struct sockaddr_in6*)&addr1; + in6_2 = (struct sockaddr_in6*)&addr2; + return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr); + default: + return false; + } + } else { + return false; + } +} + +void CNetUtils::setPort(struct sockaddr_storage& addr, in_port_t port) +{ + switch (addr.ss_family) + { + case AF_INET: + TOIPV4(addr)->sin_port = port; + break; + case AF_INET6: + TOIPV6(addr)->sin6_port = port; + default: + break; + } +} diff --git a/NetUtils.h b/NetUtils.h index b3dd779..1578c97 100644 --- a/NetUtils.h +++ b/NetUtils.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,10 +23,21 @@ #include #include + +#define GETPORT(s) (s.ss_family == AF_INET6 ? TOIPV6(s)->sin6_port : TOIPV4(s)->sin_port) + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + class CNetUtils { public: static bool lookupV6(const std::string& hostname, sockaddr_storage& addr); static bool lookupV4(const std::string& hostname, sockaddr_storage& addr); + static bool lookup(const std::string& hostname, sockaddr_storage& addr); static bool lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints); + static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type); + static void setPort(struct sockaddr_storage& addr, in_port_t port); }; \ No newline at end of file diff --git a/Tests/NetUtils/match.cpp b/Tests/NetUtils/match.cpp new file mode 100644 index 0000000..0f58d12 --- /dev/null +++ b/Tests/NetUtils/match.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include + +#include "../../NetUtils.h" + +namespace NetUtilsTests +{ + class NetUtils_match: public ::testing::Test { + + }; + + TEST_F(NetUtils_match, MatchIPAndPort_differentFamilySamePort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in *)&addr2)->sin_addr.s_addr = INADDR_LOOPBACK; + ((struct sockaddr_in *)&addr2)->sin_port = 123; + + EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIPAndPort_SameFamilySamePort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 123; + + EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIPAndPort_SameFamilyDifferentPort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 456; + + EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIP_SameFamilyDifferentPort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 456; + + EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_ONLY)); + } +} \ No newline at end of file