]> git.seodisparate.com - UDPConnection/commitdiff
Add support for UDPC_strtoa to accept ipv4 input
authorStephen Seo <seo.disparate@gmail.com>
Tue, 17 Sep 2019 08:17:16 +0000 (17:17 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Tue, 17 Sep 2019 08:17:16 +0000 (17:17 +0900)
UDPC_strtoa can now return an ipv4-mapped ipv6 address given an ipv4
string. Also, added validation of input strings via regex.

cpp_impl/src/UDPConnection.cpp
cpp_impl/src/UDPConnection.h
cpp_impl/src/test/TestUDPC.cpp

index a52dddddbf2fcbd80f07487fda0770a67e0a28b9..e9675de7d654a6ce41bde728cf15c919b7e5a309 100644 (file)
 #include <string>
 #include <sstream>
 #include <ios>
+#include <regex>
+
+static std::regex ipv6_regex = std::regex(R"d((([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))d");
+// TODO remove ipv6_regex_nolink when link device is supported
+static std::regex ipv6_regex_nolink = std::regex(R"d((([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))d");
+static std::regex ipv4_regex = std::regex(R"d((1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])\.(1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])\.(1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])\.(1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9]))d");
 
 UDPC::SentPktInfo::SentPktInfo() :
 id(0),
@@ -1117,171 +1123,183 @@ const char *UDPC_atostr(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
 }
 
 struct in6_addr UDPC_strtoa(const char *addrStr) {
-    struct in6_addr result{{0}};
-    unsigned int index = 0;
-    unsigned int strIndex = 0;
-    int doubleColonIndex = -1;
-    unsigned char bytes[2] = {0, 0};
-    unsigned char bytesState = 0;
-    bool prevColon = false;
-
-    const auto checkInc = [&result, &index, &bytes] () -> bool {
-        if(index < 15) {
-            result.s6_addr[index++] = bytes[0];
-            result.s6_addr[index++] = bytes[1];
-            bytes[0] = 0;
-            bytes[1] = 0;
-            return false;
-        }
-        return true;
-    };
-
-    while(addrStr[strIndex] != '\0') {
-        if(addrStr[strIndex] >= '0' && addrStr[strIndex] <= '9') {
-            switch(bytesState) {
-            case 0:
-                bytes[0] = (addrStr[strIndex] - '0');
-                bytesState = 1;
-                break;
-            case 1:
-                bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - '0');
-                bytesState = 2;
-                break;
-            case 2:
-                bytes[1] = (addrStr[strIndex] - '0');
-                bytesState = 3;
-                break;
-            case 3:
-                bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - '0');
-                bytesState = 0;
-                if(checkInc()) {
-                    return in6addr_loopback;
-                }
-                break;
-            default:
-                return in6addr_loopback;
+    struct in6_addr result = in6addr_loopback;
+    std::cmatch matchResults;
+    // TODO switch regex to ipv6_regex when link device is supported
+    if(std::regex_match(addrStr, matchResults, ipv6_regex_nolink)) {
+        unsigned int index = 0;
+        unsigned int strIndex = 0;
+        int doubleColonIndex = -1;
+        unsigned char bytes[2] = {0, 0};
+        unsigned char bytesState = 0;
+        bool prevColon = false;
+
+        const auto checkInc = [&result, &index, &bytes] () -> bool {
+            if(index < 15) {
+                result.s6_addr[index++] = bytes[0];
+                result.s6_addr[index++] = bytes[1];
+                bytes[0] = 0;
+                bytes[1] = 0;
+                return false;
             }
-            prevColon = false;
-        } else if(addrStr[strIndex] >= 'a' && addrStr[strIndex] <= 'f') {
-            switch(bytesState) {
-            case 0:
-                bytes[0] = (addrStr[strIndex] - 'a' + 10);
-                bytesState = 1;
-                break;
-            case 1:
-                bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'a' + 10);
-                bytesState = 2;
-                break;
-            case 2:
-                bytes[1] = (addrStr[strIndex] - 'a' + 10);
-                bytesState = 3;
-                break;
-            case 3:
-                bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'a' + 10);
-                bytesState = 0;
-                if(checkInc()) {
+            return true;
+        };
+
+        while(addrStr[strIndex] != '\0') {
+            if(addrStr[strIndex] >= '0' && addrStr[strIndex] <= '9') {
+                switch(bytesState) {
+                case 0:
+                    bytes[0] = (addrStr[strIndex] - '0');
+                    bytesState = 1;
+                    break;
+                case 1:
+                    bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - '0');
+                    bytesState = 2;
+                    break;
+                case 2:
+                    bytes[1] = (addrStr[strIndex] - '0');
+                    bytesState = 3;
+                    break;
+                case 3:
+                    bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - '0');
+                    bytesState = 0;
+                    if(checkInc()) {
+                        return in6addr_loopback;
+                    }
+                    break;
+                default:
                     return in6addr_loopback;
                 }
-                break;
-            default:
-                return in6addr_loopback;
-            }
-            prevColon = false;
-        } else if(addrStr[strIndex] >= 'A' && addrStr[strIndex] <= 'F') {
-            switch(bytesState) {
-            case 0:
-                bytes[0] = (addrStr[strIndex] - 'A' + 10);
-                bytesState = 1;
-                break;
-            case 1:
-                bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'A' + 10);
-                bytesState = 2;
-                break;
-            case 2:
-                bytes[1] = (addrStr[strIndex] - 'A' + 10);
-                bytesState = 3;
-                break;
-            case 3:
-                bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'A' + 10);
-                bytesState = 0;
-                if(checkInc()) {
+                prevColon = false;
+            } else if(addrStr[strIndex] >= 'a' && addrStr[strIndex] <= 'f') {
+                switch(bytesState) {
+                case 0:
+                    bytes[0] = (addrStr[strIndex] - 'a' + 10);
+                    bytesState = 1;
+                    break;
+                case 1:
+                    bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'a' + 10);
+                    bytesState = 2;
+                    break;
+                case 2:
+                    bytes[1] = (addrStr[strIndex] - 'a' + 10);
+                    bytesState = 3;
+                    break;
+                case 3:
+                    bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'a' + 10);
+                    bytesState = 0;
+                    if(checkInc()) {
+                        return in6addr_loopback;
+                    }
+                    break;
+                default:
                     return in6addr_loopback;
                 }
-                break;
-            default:
-                return in6addr_loopback;
-            }
-            prevColon = false;
-        } else if(addrStr[strIndex] == ':') {
-            switch(bytesState) {
-            case 1:
-            case 2:
-                bytes[1] = bytes[0];
-                bytes[0] = 0;
-                if(checkInc()) {
+                prevColon = false;
+            } else if(addrStr[strIndex] >= 'A' && addrStr[strIndex] <= 'F') {
+                switch(bytesState) {
+                case 0:
+                    bytes[0] = (addrStr[strIndex] - 'A' + 10);
+                    bytesState = 1;
+                    break;
+                case 1:
+                    bytes[0] = (bytes[0] << 4) | (addrStr[strIndex] - 'A' + 10);
+                    bytesState = 2;
+                    break;
+                case 2:
+                    bytes[1] = (addrStr[strIndex] - 'A' + 10);
+                    bytesState = 3;
+                    break;
+                case 3:
+                    bytes[1] = (bytes[1] << 4) | (addrStr[strIndex] - 'A' + 10);
+                    bytesState = 0;
+                    if(checkInc()) {
+                        return in6addr_loopback;
+                    }
+                    break;
+                default:
                     return in6addr_loopback;
                 }
-                break;
-            case 3:
-                bytes[1] |= (bytes[0] & 0xF) << 4;
-                bytes[0] = bytes[0] >> 4;
-                if(checkInc()) {
+                prevColon = false;
+            } else if(addrStr[strIndex] == ':') {
+                switch(bytesState) {
+                case 1:
+                case 2:
+                    bytes[1] = bytes[0];
+                    bytes[0] = 0;
+                    if(checkInc()) {
+                        return in6addr_loopback;
+                    }
+                    break;
+                case 3:
+                    bytes[1] |= (bytes[0] & 0xF) << 4;
+                    bytes[0] = bytes[0] >> 4;
+                    if(checkInc()) {
+                        return in6addr_loopback;
+                    }
+                    break;
+                case 0:
+                    break;
+                default:
                     return in6addr_loopback;
                 }
-                break;
-            case 0:
-                break;
-            default:
-                return in6addr_loopback;
-            }
-            bytesState = 0;
-            if(prevColon) {
-                if(doubleColonIndex >= 0) {
-                    return in6addr_loopback;
+                bytesState = 0;
+                if(prevColon) {
+                    if(doubleColonIndex >= 0) {
+                        return in6addr_loopback;
+                    } else {
+                        doubleColonIndex = index;
+                    }
                 } else {
-                    doubleColonIndex = index;
+                    prevColon = true;
                 }
             } else {
-                prevColon = true;
+                return in6addr_loopback;
             }
-        } else {
-            return in6addr_loopback;
-        }
 
-        ++strIndex;
-    }
-    switch(bytesState) {
-    case 1:
-    case 2:
-        bytes[1] = bytes[0];
-        bytes[0] = 0;
-        if(checkInc()) {
-            return in6addr_loopback;
+            ++strIndex;
         }
-        break;
-    case 3:
-        bytes[1] |= (bytes[0] & 0xF) << 4;
-        bytes[0] = bytes[0] >> 4;
-        if(checkInc()) {
+        switch(bytesState) {
+        case 1:
+        case 2:
+            bytes[1] = bytes[0];
+            bytes[0] = 0;
+            if(checkInc()) {
+                return in6addr_loopback;
+            }
+            break;
+        case 3:
+            bytes[1] |= (bytes[0] & 0xF) << 4;
+            bytes[0] = bytes[0] >> 4;
+            if(checkInc()) {
+                return in6addr_loopback;
+            }
+            break;
+        case 0:
+            break;
+        default:
             return in6addr_loopback;
         }
-        break;
-    case 0:
-        break;
-    default:
-        return in6addr_loopback;
-    }
 
-    if(doubleColonIndex >= 0) {
-        strIndex = 16 - index;
-        if(strIndex < 2) {
-            return in6addr_loopback;
+        if(doubleColonIndex >= 0) {
+            strIndex = 16 - index;
+            if(strIndex < 2) {
+                return in6addr_loopback;
+            }
+            for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
+                result.s6_addr[i] = result.s6_addr[i - strIndex];
+                result.s6_addr[i - strIndex] = 0;
+            }
         }
-        for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
-            result.s6_addr[i] = result.s6_addr[i - strIndex];
-            result.s6_addr[i - strIndex] = 0;
+    } else if(std::regex_match(addrStr, matchResults, ipv4_regex)) {
+        for(unsigned int i = 0; i < 10; ++i) {
+            result.s6_addr[i] = 0;
+        }
+        result.s6_addr[10] = 0xFF;
+        result.s6_addr[11] = 0xFF;
+        for(unsigned int i = 0; i < 4; ++i) {
+            result.s6_addr[12 + i] = std::stoi(matchResults[i + 1].str());
         }
     }
-
     return result;
 }
index 9533b2a81e817be78f957bfde0eb3d755c0b895c..ebe25b2045e76da347c3f6dffe14ba4bab314ae1 100644 (file)
@@ -102,6 +102,7 @@ UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx);
 
 const char *UDPC_atostr(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
 
+/// addrStr must be a valid ipv6 address or a valid ipv4 address
 struct in6_addr UDPC_strtoa(const char *addrStr);
 
 #ifdef __cplusplus
index e85c5d0eb1f0c21ed897b844d895eff20b42b046..779ffd9e00bd2595ef5542cf93a44aabc3e19472 100644 (file)
@@ -172,4 +172,20 @@ TEST(UDPC, strtoa) {
         0x12, 0x34, 0xab, 0xcd
     };
     EXPECT_EQ(UDPC_strtoa("ff:100:1:1000::1234:abcd"), addr);
+
+    addr = {
+        0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0xFF, 0xFF,
+        0x7F, 0x0, 0x0, 0x1
+    };
+    EXPECT_EQ(UDPC_strtoa("127.0.0.1"), addr);
+
+    addr = {
+        0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0x0, 0x0,
+        0x0, 0x0, 0xFF, 0xFF,
+        0xA, 0x1, 0x2, 0x3
+    };
+    EXPECT_EQ(UDPC_strtoa("10.1.2.3"), addr);
 }