shill: IPAddress: Add a few address manipulation utilities
Add a few address operations to test whether one address can
be reached directly from another.
BUG=chromium-os:29416
TEST=New unit tests
Change-Id: I5600a225b44edc1fbacb167488f4187e9aa99937
Reviewed-on: https://gerrit.chromium.org/gerrit/20464
Commit-Ready: Paul Stewart <pstew@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/ip_address.cc b/ip_address.cc
index 1e36d55..52a4aab 100644
--- a/ip_address.cc
+++ b/ip_address.cc
@@ -8,15 +8,23 @@
#include <netinet/in.h>
#include <string>
+#include <vector>
#include <base/logging.h>
+#include <base/string_number_conversions.h>
+#include <base/string_split.h>
#include "shill/byte_string.h"
using std::string;
+using std::vector;
namespace shill {
+namespace {
+const size_t kBitsPerByte = 8;
+} // namespace
+
// static
const IPAddress::Family IPAddress::kFamilyUnknown = AF_UNSPEC;
// static
@@ -63,7 +71,30 @@
// static
size_t IPAddress::GetMaxPrefixLength(Family family) {
- return GetAddressLength(family) * 8;
+ return GetAddressLength(family) * kBitsPerByte;
+}
+
+size_t IPAddress::GetMinPrefixLength() const {
+ if (family() != kFamilyIPv4) {
+ NOTIMPLEMENTED() << ": only implemented for IPv4";
+ return GetMaxPrefixLength(family());
+ }
+
+ CHECK(IsValid());
+ in_addr_t address_val;
+ memcpy(&address_val, GetConstData(), sizeof(address_val));
+ // IN_CLASSx() macros operate on addresses in host-order.
+ address_val = ntohl(address_val);
+ if (IN_CLASSA(address_val)) {
+ return GetMaxPrefixLength(family()) - IN_CLASSA_NSHIFT;
+ } else if (IN_CLASSB(address_val)) {
+ return GetMaxPrefixLength(family()) - IN_CLASSB_NSHIFT;
+ } else if (IN_CLASSC(address_val)) {
+ return GetMaxPrefixLength(family()) - IN_CLASSC_NSHIFT;
+ }
+
+ LOG(ERROR) << "Invalid IPv4 address class";
+ return GetMaxPrefixLength(family());
}
// static
@@ -89,6 +120,29 @@
}
// static
+IPAddress IPAddress::GetAddressMaskFromPrefix(Family family, size_t prefix) {
+ ByteString address_bytes(GetAddressLength(family));
+ unsigned char *address_ptr = address_bytes.GetData();
+
+ size_t bits = prefix;
+ if (bits > GetMaxPrefixLength(family)) {
+ bits = GetMaxPrefixLength(family);
+ }
+
+ while (bits > kBitsPerByte) {
+ bits -= kBitsPerByte;
+ *address_ptr++ = kuint8max;
+ }
+
+ // We are guaranteed to be before the end of the address data since even
+ // if the prefix is the maximum, the loop above will end before we assign
+ // and increment past the last byte.
+ *address_ptr = ~((1 << (kBitsPerByte - bits)) - 1);
+
+ return IPAddress(family, address_bytes);
+}
+
+// static
string IPAddress::GetAddressFamilyName(Family family) {
switch (family) {
case kFamilyIPv4:
@@ -115,6 +169,26 @@
return true;
}
+bool IPAddress::SetAddressAndPrefixFromString(const string &address_string) {
+ vector<string> address_parts;
+ base::SplitString(address_string, '/', &address_parts);
+ if (address_parts.size() != 2) {
+ LOG(ERROR) << "Cannot split address " << address_string;
+ return false;
+ }
+ if (!SetAddressFromString(address_parts[0])) {
+ LOG(ERROR) << "Cannot parse address string " << address_parts[0];
+ return false;
+ }
+ int prefix;
+ if (!base::StringToInt(address_parts[1], &prefix) || prefix < 0) {
+ LOG(ERROR) << "Cannot parse address prefix " << address_parts[1];
+ return false;
+ }
+ set_prefix(prefix);
+ return true;
+}
+
void IPAddress::SetAddressToDefault() {
address_ = ByteString(GetAddressLength(family_));
}
@@ -136,4 +210,26 @@
return out;
}
+IPAddress IPAddress::MaskWith(const IPAddress &b) {
+ CHECK(IsValid());
+ CHECK(b.IsValid());
+ CHECK_EQ(family(), b.family());
+
+ ByteString address_bytes(address());
+ address_bytes.ApplyMask(b.address());
+
+ return IPAddress(family(), address_bytes);
+}
+
+IPAddress IPAddress::GetNetworkPart() {
+ return MaskWith(GetAddressMaskFromPrefix(family(), prefix()));
+}
+
+bool IPAddress::CanReachAddress(const IPAddress &b) {
+ CHECK_EQ(family(), b.family());
+ IPAddress b_prefixed(b);
+ b_prefixed.set_prefix(prefix());
+ return GetNetworkPart().Equals(b_prefixed.GetNetworkPart());
+}
+
} // namespace shill