Merge "netd_integration_test:BinderTest#GetFwmarkForNetwork - save/restore default network"
diff --git a/libnetdutils/InternetAddresses.cpp b/libnetdutils/InternetAddresses.cpp
index 78d30b2..322f1b1 100644
--- a/libnetdutils/InternetAddresses.cpp
+++ b/libnetdutils/InternetAddresses.cpp
@@ -16,6 +16,8 @@
 
 #include "netdutils/InternetAddresses.h"
 
+#include <string>
+
 #include <android-base/stringprintf.h>
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -123,6 +125,28 @@
     return mData == empty;
 }
 
+bool IPPrefix::forString(const std::string& repr, IPPrefix* prefix) {
+    size_t index = repr.find('/');
+    if (index == std::string::npos) return false;
+
+    // Parse the IP address.
+    IPAddress ip;
+    if (!IPAddress::forString(repr.substr(0, index), &ip)) return false;
+
+    // Parse the prefix length. Can't use base::ParseUint because it accepts non-base 10 input.
+    const char* prefixString = repr.c_str() + index + 1;
+    if (!isdigit(*prefixString)) return false;
+    char* endptr;
+    unsigned long prefixlen = strtoul(prefixString, &endptr, 10);
+    if (*endptr != '\0') return false;
+
+    uint8_t maxlen = (ip.family() == AF_INET) ? 32 : 128;
+    if (prefixlen > maxlen) return false;
+
+    *prefix = IPPrefix(ip, prefixlen);
+    return true;
+}
+
 std::string IPPrefix::toString() const noexcept {
     return StringPrintf("%s/%d", ip().toString().c_str(), mData.cidrlen);
 }
diff --git a/libnetdutils/InternetAddressesTest.cpp b/libnetdutils/InternetAddressesTest.cpp
index 2129ca7..f75fa76 100644
--- a/libnetdutils/InternetAddressesTest.cpp
+++ b/libnetdutils/InternetAddressesTest.cpp
@@ -171,6 +171,43 @@
     EXPECT_EQ(IPAddress(FE80_1, 1), IPAddress::forString("fe80::1%lo"));
 }
 
+TEST(IPPrefixTest, forString) {
+    IPPrefix prefix;
+
+    EXPECT_FALSE(IPPrefix::forString("", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("invalid", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("192.0.2.0", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001::db8::", &prefix));
+
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8:://32", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32z", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32/", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/0x20", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8:: /32", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/ 32", &prefix));
+    EXPECT_FALSE(IPPrefix::forString(" 2001:db8::/32", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/32 ", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/+32", &prefix));
+
+    EXPECT_FALSE(IPPrefix::forString("192.0.2.0/33", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/129", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("192.0.2.0/-1", &prefix));
+    EXPECT_FALSE(IPPrefix::forString("2001:db8::/-1", &prefix));
+
+    EXPECT_TRUE(IPPrefix::forString("2001:db8::/32", &prefix));
+    EXPECT_EQ("2001:db8::/32", prefix.toString());
+    EXPECT_EQ(IPPrefix(IPAddress::forString("2001:db8::"), 32), prefix);
+
+    EXPECT_EQ(IPPrefix(), IPPrefix::forString("invalid"));
+
+    EXPECT_EQ("0.0.0.0/0", IPPrefix::forString("0.0.0.0/0").toString());
+    EXPECT_EQ("::/0", IPPrefix::forString("::/0").toString());
+    EXPECT_EQ("192.0.2.128/25", IPPrefix::forString("192.0.2.131/25").toString());
+    EXPECT_EQ("2001:db8:1:2:3:4:5:4/126",
+              IPPrefix::forString("2001:db8:1:2:3:4:5:6/126").toString());
+}
+
 TEST(IPPrefixTest, IPv4Truncation) {
     const auto prefixStr = [](int length) -> std::string {
         return IPPrefix(IPAddress(IPV4_ONES), length).toString();
diff --git a/libnetdutils/include/netdutils/InternetAddresses.h b/libnetdutils/include/netdutils/InternetAddresses.h
index e817b78..d5cbe2b 100644
--- a/libnetdutils/include/netdutils/InternetAddresses.h
+++ b/libnetdutils/include/netdutils/InternetAddresses.h
@@ -195,7 +195,12 @@
 
 class IPPrefix {
   public:
-    // TODO: "static forString(...)" using NetdConstants' parsePrefix().
+    static bool forString(const std::string& repr, IPPrefix* prefix);
+    static IPPrefix forString(const std::string& repr) {
+        IPPrefix prefix;
+        if (!forString(repr, &prefix)) return IPPrefix();
+        return prefix;
+    }
 
     IPPrefix() = default;
     IPPrefix(const IPPrefix&) = default;