Skip to content

Commit 1dac676

Browse files
author
Arto Kinnunen
committed
Merge commit '7d2f0cab63a2223a426c44e13f771abe6a7d7eaf'
* commit '7d2f0cab63a2223a426c44e13f771abe6a7d7eaf': Squashed 'features/frameworks/nanostack-libservice/' changes from 2705b9b..5eb2f3f
2 parents ea2dec0 + 7d2f0ca commit 1dac676

File tree

5 files changed

+216
-44
lines changed

5 files changed

+216
-44
lines changed

features/frameworks/nanostack-libservice/mbed-client-libservice/ip6string.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p
5858
*
5959
* \param ip6addr IPv6 address in string format.
6060
* \param len Lenght of ipv6 string, maximum of 41.
61-
* \param dest buffer for address. MUST be 16 bytes.
61+
* \param dest buffer for address. MUST be 16 bytes. Filled with 0 on error.
62+
* \return boolean set to true if conversion succeed, false if it didn't
6263
*/
63-
void stoip6(const char *ip6addr, size_t len, void *dest);
64+
bool stoip6(const char *ip6addr, size_t len, void *dest);
6465
/**
6566
* Find out numeric IPv6 address prefix length.
6667
*
@@ -69,6 +70,19 @@ void stoip6(const char *ip6addr, size_t len, void *dest);
6970
*/
7071
unsigned char sipv6_prefixlength(const char *ip6addr);
7172

73+
/**
74+
* Convert numeric IPv6 address string with prefix to a binary.
75+
*
76+
* IPv4 tunneling addresses are not covered.
77+
*
78+
* \param ip6addr IPv6 address in string format.
79+
* \param dest buffer for address. MUST be 16 bytes.
80+
* \param prefix_len_out length of prefix, is set to -1 if no prefix given
81+
*
82+
* \return 0 on success, negative value otherwise. prefix_len_out contains prefix length.
83+
*/
84+
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out);
85+
7286
#ifdef __cplusplus
7387
}
7488
#endif

features/frameworks/nanostack-libservice/source/libip6string/stoip6.c

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@
2020
#include "ip6string.h"
2121

2222
static uint16_t hex(const char *p);
23+
static bool is_hex(char c);
2324

2425
/**
2526
* Convert numeric IPv6 address string to a binary.
2627
* IPv4 tunnelling addresses are not covered.
2728
* \param ip6addr IPv6 address in string format.
2829
* \param len Length of ipv6 string.
2930
* \param dest buffer for address. MUST be 16 bytes.
31+
* \return boolean set to true if conversion succeed, false if it didn't
3032
*/
31-
void stoip6(const char *ip6addr, size_t len, void *dest)
33+
bool stoip6(const char *ip6addr, size_t len, void *dest)
3234
{
3335
uint8_t *addr;
3436
const char *p, *q;
@@ -37,23 +39,45 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
3739
addr = dest;
3840

3941
if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
40-
return;
42+
goto error;
4143
}
4244

4345
// First go forward the string, until end, noting :: position if any
44-
for (field_no = 0, p = ip6addr; (len > (size_t)(p - ip6addr)) && *p && field_no < 8; p = q + 1) {
45-
q = p;
46-
// Seek for ':' or end
47-
while (*q && (*q != ':')) {
48-
q++;
46+
// We're decrementing `len` as we go forward, and stop when it reaches 0
47+
for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
48+
49+
for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
50+
if (!is_hex(*q++)) { // There must only be hex characters besides ':'
51+
goto error;
52+
}
53+
}
54+
55+
if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
56+
goto error;
57+
}
58+
59+
if (field_no == 8) { // If the address goes farther than 8 segments
60+
goto error;
4961
}
50-
//Convert and write this part, (high-endian AKA network byte order)
62+
63+
// Convert and write this part, (high-endian AKA network byte order)
5164
addr = common_write_16_bit(hex(p), addr);
5265
field_no++;
53-
//Check if we reached "::"
54-
if ((len > (size_t)(q - ip6addr)) && *q && (q[0] == ':') && (q[1] == ':')) {
55-
coloncolon = field_no;
56-
q++;
66+
67+
// We handle the colons
68+
if (len) {
69+
// Check if we reached "::"
70+
if (q[0] == ':' && q[1] == ':') {
71+
if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
72+
goto error;
73+
}
74+
coloncolon = field_no;
75+
q++;
76+
len -= 2;
77+
}
78+
else {
79+
len -= 1;
80+
}
5781
}
5882
}
5983

@@ -65,19 +89,76 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
6589
addr = dest;
6690
memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
6791
memset(addr + head_size, 0, inserted_size);
68-
} else if (field_no != 8) {
69-
/* Should really report an error if we didn't get 8 fields */
70-
memset(addr, 0, 16 - field_no * 2);
92+
} else if (field_no != 8) { // Report an error if we didn't get 8 fields
93+
goto error;
7194
}
95+
return true;
96+
97+
error:
98+
// Fill the output buffer with 0 so we stick to the old failure behavior.
99+
// We are however more agressive and wipe the entire address, and do so more often.
100+
memset(dest, 0, 16);
101+
return false;
72102
}
73-
unsigned char sipv6_prefixlength(const char *ip6addr)
103+
104+
unsigned char sipv6_prefixlength(const char *ip6addr)
74105
{
75106
char *ptr = strchr(ip6addr, '/');
76107
if (ptr) {
77108
return (unsigned char)strtoul(ptr + 1, 0, 10);
78109
}
79110
return 0;
80111
}
112+
113+
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
114+
{
115+
size_t addr_len, total_len;
116+
int_fast16_t prefix_length;
117+
118+
if (prefix_len_out) {
119+
*prefix_len_out = -1;
120+
}
121+
122+
total_len = addr_len = strlen(ip6addr);
123+
const char *ptr = strchr(ip6addr, '/');
124+
if (ptr) {
125+
addr_len = ptr - ip6addr;
126+
if (prefix_len_out) {
127+
if (total_len - addr_len > 3) {
128+
/* too many digits in prefix */
129+
return -1;
130+
}
131+
132+
prefix_length = strtoul(ptr + 1, 0, 10);
133+
if (prefix_length < 0 || prefix_length > 128) {
134+
/* prefix value illegal */
135+
return -1;
136+
}
137+
138+
*prefix_len_out = prefix_length;
139+
}
140+
}
141+
142+
if (!stoip6(ip6addr, addr_len, dest)) {
143+
/* parser failure */
144+
return -1;
145+
}
146+
147+
return 0;
148+
}
149+
150+
static bool is_hex(char c)
151+
{
152+
// 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
153+
if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F')
154+
return true;
155+
156+
if (c >= '0' && c <= '9')
157+
return true;
158+
159+
return false;
160+
}
161+
81162
static uint16_t hex(const char *p)
82163
{
83164
uint16_t val = 0;

features/frameworks/nanostack-libservice/test/libService/unittest/stoip6/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ int main(int ac, char **av)
2525

2626
IMPORT_TEST_GROUP(stoip6);
2727
IMPORT_TEST_GROUP(stoip6_2);
28+
IMPORT_TEST_GROUP(stoip6_3);

0 commit comments

Comments
 (0)