Merge pull request #8245 from artokin/nanostack_libservice_update

Nanostack libservice update
pull/8364/merge
Cruz Monrreal 2018-10-10 08:44:09 -05:00 committed by GitHub
commit d58f241b75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 216 additions and 44 deletions

View File

@ -58,9 +58,10 @@ uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p
*
* \param ip6addr IPv6 address in string format.
* \param len Lenght of ipv6 string, maximum of 41.
* \param dest buffer for address. MUST be 16 bytes.
* \param dest buffer for address. MUST be 16 bytes. Filled with 0 on error.
* \return boolean set to true if conversion succeed, false if it didn't
*/
void stoip6(const char *ip6addr, size_t len, void *dest);
bool stoip6(const char *ip6addr, size_t len, void *dest);
/**
* Find out numeric IPv6 address prefix length.
*
@ -69,6 +70,19 @@ void stoip6(const char *ip6addr, size_t len, void *dest);
*/
unsigned char sipv6_prefixlength(const char *ip6addr);
/**
* Convert numeric IPv6 address string with prefix to a binary.
*
* IPv4 tunneling addresses are not covered.
*
* \param ip6addr IPv6 address in string format.
* \param dest buffer for address. MUST be 16 bytes.
* \param prefix_len_out length of prefix, is set to -1 if no prefix given
*
* \return 0 on success, negative value otherwise. prefix_len_out contains prefix length.
*/
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out);
#ifdef __cplusplus
}
#endif

View File

@ -20,6 +20,7 @@
#include "ip6string.h"
static uint16_t hex(const char *p);
static bool is_hex(char c);
/**
* Convert numeric IPv6 address string to a binary.
@ -27,8 +28,9 @@ static uint16_t hex(const char *p);
* \param ip6addr IPv6 address in string format.
* \param len Length of ipv6 string.
* \param dest buffer for address. MUST be 16 bytes.
* \return boolean set to true if conversion succeed, false if it didn't
*/
void stoip6(const char *ip6addr, size_t len, void *dest)
bool stoip6(const char *ip6addr, size_t len, void *dest)
{
uint8_t *addr;
const char *p, *q;
@ -37,23 +39,45 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
addr = dest;
if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
return;
goto error;
}
// First go forward the string, until end, noting :: position if any
for (field_no = 0, p = ip6addr; (len > (size_t)(p - ip6addr)) && *p && field_no < 8; p = q + 1) {
q = p;
// Seek for ':' or end
while (*q && (*q != ':')) {
q++;
// We're decrementing `len` as we go forward, and stop when it reaches 0
for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
if (!is_hex(*q++)) { // There must only be hex characters besides ':'
goto error;
}
}
//Convert and write this part, (high-endian AKA network byte order)
if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
goto error;
}
if (field_no == 8) { // If the address goes farther than 8 segments
goto error;
}
// Convert and write this part, (high-endian AKA network byte order)
addr = common_write_16_bit(hex(p), addr);
field_no++;
//Check if we reached "::"
if ((len > (size_t)(q - ip6addr)) && *q && (q[0] == ':') && (q[1] == ':')) {
coloncolon = field_no;
q++;
// We handle the colons
if (len) {
// Check if we reached "::"
if (q[0] == ':' && q[1] == ':') {
if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
goto error;
}
coloncolon = field_no;
q++;
len -= 2;
}
else {
len -= 1;
}
}
}
@ -65,12 +89,19 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
addr = dest;
memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
memset(addr + head_size, 0, inserted_size);
} else if (field_no != 8) {
/* Should really report an error if we didn't get 8 fields */
memset(addr, 0, 16 - field_no * 2);
} else if (field_no != 8) { // Report an error if we didn't get 8 fields
goto error;
}
return true;
error:
// Fill the output buffer with 0 so we stick to the old failure behavior.
// We are however more agressive and wipe the entire address, and do so more often.
memset(dest, 0, 16);
return false;
}
unsigned char sipv6_prefixlength(const char *ip6addr)
unsigned char sipv6_prefixlength(const char *ip6addr)
{
char *ptr = strchr(ip6addr, '/');
if (ptr) {
@ -78,6 +109,56 @@ unsigned char sipv6_prefixlength(const char *ip6addr)
}
return 0;
}
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
{
size_t addr_len, total_len;
int_fast16_t prefix_length;
if (prefix_len_out) {
*prefix_len_out = -1;
}
total_len = addr_len = strlen(ip6addr);
const char *ptr = strchr(ip6addr, '/');
if (ptr) {
addr_len = ptr - ip6addr;
if (prefix_len_out) {
if (total_len - addr_len > 3) {
/* too many digits in prefix */
return -1;
}
prefix_length = strtoul(ptr + 1, 0, 10);
if (prefix_length < 0 || prefix_length > 128) {
/* prefix value illegal */
return -1;
}
*prefix_len_out = prefix_length;
}
}
if (!stoip6(ip6addr, addr_len, dest)) {
/* parser failure */
return -1;
}
return 0;
}
static bool is_hex(char c)
{
// 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F')
return true;
if (c >= '0' && c <= '9')
return true;
return false;
}
static uint16_t hex(const char *p)
{
uint16_t val = 0;

View File

@ -25,3 +25,4 @@ int main(int ac, char **av)
IMPORT_TEST_GROUP(stoip6);
IMPORT_TEST_GROUP(stoip6_2);
IMPORT_TEST_GROUP(stoip6_3);

View File

@ -42,11 +42,10 @@ TEST(stoip6, TooShort)
{
char *addr = "FFFF:FFFF:";
uint8_t ip[16];
uint8_t correct[16] = {0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// This should sto parsing when too short address given, the buffer hoewever is filled to that long
// So basically there is no error handling. We just check that first FFFF:FFFF gets filled and not trash after that.
// Rest should be filled with zeroes
stoip6(addr, strlen(addr), ip);
uint8_t correct[16] = {0};
// This should stop parsing when too short address given.
// Despite partial parsing, the entire buffer should be filled with zeroes
CHECK(false == stoip6(addr, strlen(addr), ip));
CHECK(0 == memcmp(ip, correct, 16));
}
@ -58,7 +57,7 @@ TEST(stoip6, TooLongString)
uint8_t correct[16] = {0};
// This should not fill anything, too long string.
// This is basically only validation we do
stoip6(addr, strlen(addr), ip);
CHECK(false == stoip6(addr, strlen(addr), ip));
CHECK(0 == memcmp(ip, correct, 16));
}
@ -66,12 +65,11 @@ TEST(stoip6, TooManyFields)
{
// String len must be less than 40
char *addr = "FF:FF:FF:FF:FF:FF:FFFF:FFFF:FFFF:FFFF:";
uint8_t ip[17] = {0};
uint8_t correct[17] = { 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
// Again.. there is not really any error handling (no return value)
// Just make sure that it does not overflow
stoip6(addr, strlen(addr), ip);
CHECK(0 == memcmp(ip, correct, 17)); // Note, we are checking 17, to make sure one byte after address in not touched.
uint8_t ip[16] = {0};
uint8_t correct[16] = {0};
CHECK(false == stoip6(addr, strlen(addr), ip));
CHECK(0 == memcmp(ip, correct, 16));
}
TEST(stoip6, Prefixlen)
@ -96,13 +94,31 @@ TEST(stoip6, RegressionTestForOffByOne)
0x64, 0x3f, 0xf5, 0x4a, 0xec, 0x29, 0xcd, 0xbb
};
stoip6(sourceTemp, sourceTempLen, ip);
CHECK(true == stoip6(sourceTemp, sourceTempLen, ip));
CHECK(0 == memcmp(ip, correct, 16));
free(sourceTemp);
}
// Test various illegal formats to ensure proper rejection
TEST(stoip6, InvalidAddresses)
{
uint8_t ip[16];
uint8_t correct[16] = {0};
const char *invalidArray[] =
{
"FFFF:FFFF::FFFF::FFFF", // Two ::
"F:F:F:FqF:F:F:F:F", // Non-hex character
"F:F:F:FFFFF:F:F:F:F" // >4 hex characters in a segment
};
for (uint8_t i = 0; i < 3; ++i) {
CHECK(false == stoip6(invalidArray[i], strlen(invalidArray[i]), ip));
CHECK(0 == memcmp(ip, correct, 16));
}
}
/***********************************************************/
/* Second test group for the old tests that were once lost */
@ -161,63 +177,122 @@ TEST_GROUP(stoip6_2)
TEST(stoip6_2, test_2_1)
{
i = 0;
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_2)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_3)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_4)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_5)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_6)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_7)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_8)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_9)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
}
TEST(stoip6_2, test_2_10)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, 16));
}
TEST(stoip6_2, test_2_11)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, 16));
}
TEST(stoip6_2, test_2_12)
{
stoip6(string_addr[i], strlen(string_addr[i]), buf);
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
CHECK(0 == memcmp(hex_addr[i], buf, 16));
}
/***********************************************************/
/* Third test group for stoip6_prefix */
const char string_prefix_addr[][40] =
{
"2001:db8::1:0:0:1/64", // 1
"2001::/60", // 2
"::1/48", // 3
"::/00", // 4
"2002::02/99", // 5
"2003::03/", // 6
"2004::04", // 7
"2005::05/2000", // 8
"2005::05/-1", // 9
};
const uint8_t hex_prefix_addr[][16] =
{
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, // 1
{ 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 2
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, // 3
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // 4
{ 0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, // 5
{ 0x20, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, // 6
{ 0x20, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 }, // 7
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 8
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 9
};
const int_fast16_t prefix_len_tbl[] = {64, 60, 48, 0, 99, 0, -1, -1, -1};
const int prefix_status_tbl[] = {0, 0, 0, 0, 0, 0, 0, -1, -1};
TEST_GROUP(stoip6_3)
{
void setup() {
}
void teardown() {
}
};
TEST(stoip6_3, stoip6_prefix_test)
{
for (int i = 0; i < 9; i++) {
uint8_t ip[16];
int_fast16_t prefix_len;
int result;
const char *addr = &string_prefix_addr[i][0];
result = stoip6_prefix(addr, ip, &prefix_len);
CHECK(result == prefix_status_tbl[i]);
if (result == 0) {
CHECK(0 == memcmp(ip, &hex_prefix_addr[i][0], 16));
CHECK(prefix_len == prefix_len_tbl[i])
}
}
}

View File

@ -33,6 +33,7 @@ struct ip6_addresses_and_its_binary_form_t {
{ "2001:db8::", { 0x20, 0x01, 0xd, 0xb8 }},
{ "::aaaa:0:0:1", { 0, 0, 0, 0, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 }},
{ "::1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }},
{ "fe80::1", { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
{ "::", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
{ "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
{NULL, {0}}