Add support for UDPC_strtoa to accept ipv4 input
UDPC_strtoa can now return an ipv4-mapped ipv6 address given an ipv4 string. Also, added validation of input strings via regex.
This commit is contained in:
parent
17d05b4a19
commit
a642db53f0
3 changed files with 186 additions and 151 deletions
|
@ -11,6 +11,12 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <ios>
|
#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() :
|
UDPC::SentPktInfo::SentPktInfo() :
|
||||||
id(0),
|
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 UDPC_strtoa(const char *addrStr) {
|
||||||
struct in6_addr result{{0}};
|
struct in6_addr result = in6addr_loopback;
|
||||||
unsigned int index = 0;
|
std::cmatch matchResults;
|
||||||
unsigned int strIndex = 0;
|
// TODO switch regex to ipv6_regex when link device is supported
|
||||||
int doubleColonIndex = -1;
|
if(std::regex_match(addrStr, matchResults, ipv6_regex_nolink)) {
|
||||||
unsigned char bytes[2] = {0, 0};
|
unsigned int index = 0;
|
||||||
unsigned char bytesState = 0;
|
unsigned int strIndex = 0;
|
||||||
bool prevColon = false;
|
int doubleColonIndex = -1;
|
||||||
|
unsigned char bytes[2] = {0, 0};
|
||||||
|
unsigned char bytesState = 0;
|
||||||
|
bool prevColon = false;
|
||||||
|
|
||||||
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
const auto checkInc = [&result, &index, &bytes] () -> bool {
|
||||||
if(index < 15) {
|
if(index < 15) {
|
||||||
result.s6_addr[index++] = bytes[0];
|
result.s6_addr[index++] = bytes[0];
|
||||||
result.s6_addr[index++] = bytes[1];
|
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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
prevColon = false;
|
|
||||||
} else if(addrStr[strIndex] == ':') {
|
|
||||||
switch(bytesState) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
bytes[1] = bytes[0];
|
|
||||||
bytes[0] = 0;
|
bytes[0] = 0;
|
||||||
if(checkInc()) {
|
bytes[1] = 0;
|
||||||
return in6addr_loopback;
|
return false;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
bytesState = 0;
|
return true;
|
||||||
if(prevColon) {
|
};
|
||||||
if(doubleColonIndex >= 0) {
|
|
||||||
|
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;
|
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()) {
|
||||||
|
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()) {
|
||||||
|
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()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
bytesState = 0;
|
||||||
|
if(prevColon) {
|
||||||
|
if(doubleColonIndex >= 0) {
|
||||||
|
return in6addr_loopback;
|
||||||
|
} else {
|
||||||
|
doubleColonIndex = index;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
doubleColonIndex = index;
|
prevColon = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prevColon = true;
|
return in6addr_loopback;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
|
++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;
|
return in6addr_loopback;
|
||||||
}
|
}
|
||||||
|
|
||||||
++strIndex;
|
if(doubleColonIndex >= 0) {
|
||||||
}
|
strIndex = 16 - index;
|
||||||
switch(bytesState) {
|
if(strIndex < 2) {
|
||||||
case 1:
|
return in6addr_loopback;
|
||||||
case 2:
|
}
|
||||||
bytes[1] = bytes[0];
|
for(unsigned int i = 16; i-- > (unsigned int)doubleColonIndex + strIndex; ) {
|
||||||
bytes[0] = 0;
|
result.s6_addr[i] = result.s6_addr[i - strIndex];
|
||||||
if(checkInc()) {
|
result.s6_addr[i - strIndex] = 0;
|
||||||
return in6addr_loopback;
|
}
|
||||||
}
|
}
|
||||||
break;
|
} else if(std::regex_match(addrStr, matchResults, ipv4_regex)) {
|
||||||
case 3:
|
for(unsigned int i = 0; i < 10; ++i) {
|
||||||
bytes[1] |= (bytes[0] & 0xF) << 4;
|
result.s6_addr[i] = 0;
|
||||||
bytes[0] = bytes[0] >> 4;
|
|
||||||
if(checkInc()) {
|
|
||||||
return in6addr_loopback;
|
|
||||||
}
|
}
|
||||||
break;
|
result.s6_addr[10] = 0xFF;
|
||||||
case 0:
|
result.s6_addr[11] = 0xFF;
|
||||||
break;
|
for(unsigned int i = 0; i < 4; ++i) {
|
||||||
default:
|
result.s6_addr[12 + i] = std::stoi(matchResults[i + 1].str());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx);
|
||||||
|
|
||||||
const char *UDPC_atostr(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
|
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);
|
struct in6_addr UDPC_strtoa(const char *addrStr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -172,4 +172,20 @@ TEST(UDPC, strtoa) {
|
||||||
0x12, 0x34, 0xab, 0xcd
|
0x12, 0x34, 0xab, 0xcd
|
||||||
};
|
};
|
||||||
EXPECT_EQ(UDPC_strtoa("ff:100:1:1000::1234:abcd"), addr);
|
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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue