1 /**
2 * @file
3 *
4 * IPv6 addresses.
5 */
6
7 /*
8 * Copyright (c) 2010 Inico Technologies Ltd.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 *
33 * This file is part of the lwIP TCP/IP stack.
34 *
35 * Author: Ivan Delamer <delamer@inicotech.com>
36 *
37 * Functions for handling IPv6 addresses.
38 *
39 * Please coordinate changes and requests with Ivan Delamer
40 * <delamer@inicotech.com>
41 */
42
43 #include "lwip/opt.h"
44
45 #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
46
47 #include "lwip/ip_addr.h"
48 #include "lwip/def.h"
49 #include "lwip/priv/sockets_priv.h"
50
51 #include <string.h>
52
53 #if LWIP_IPV4
54 /* Dual-stack: For ip6addr_aton to handle IPv4-mapped addresses */
55 #include "lwip/ip4_addr.h"
56 /* Dual-stack: IPv4 mapped header formatr */
57 #define IP4MAPPED_HEADER "::FFFF:"
58 /* Dual-stack: IPv4 compatible header formatr */
59 #define IPV4COMPATIBLE_HEADER "::"
60 #endif /* LWIP_IPV4 */
61
62 /* used by IP6_ADDR_ANY(6) in ip6_addr.h */
63 const ip_addr_t ip6_addr_any = IPADDR6_INIT(0ul, 0ul, 0ul, 0ul);
64
65 #define lwip_xchar(i) ((char)((i) < 10 ? '0' + (i) : 'A' + (i) - 10))
66
67 #define IP6_ADDR_BLOCK_SIZE_MAX 4
68
69 #if LWIP_SMALL_SIZE
70 #if LWIP_IPV6_SCOPES
71 const ip6_addr_t ip6_addr_none = {{0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL}, 0};
72 const ip6_addr_t ip6_addr_loopback = {{0, 0, 0, PP_HTONL(0x00000001UL)}, 0};
73 const ip6_addr_t ip6_addr_allnodes_iflocal = {{PP_HTONL(0xff010000UL), 0, 0, PP_HTONL(0x00000001UL)}, 0};
74 const ip6_addr_t ip6_addr_allnodes_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x00000001UL)}, 0};
75 const ip6_addr_t ip6_addr_allrpl_nodes_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x0000001aUL)}, 0};
76 const ip6_addr_t ip6_addr_mpl_ip4_bcast = {{PP_HTONL(0xff130000UL), 0, 0, PP_HTONL(0x000000fcUL)}, 0};
77 const ip6_addr_t ip6_addr_allrouters_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x00000002UL)}, 0};
78 #else
79 const ip6_addr_t ip6_addr_none = {{0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL}};
80 const ip6_addr_t ip6_addr_loopback = {{0, 0, 0, PP_HTONL(0x00000001UL)}};
81 const ip6_addr_t ip6_addr_allnodes_iflocal = {{PP_HTONL(0xff010000UL), 0, 0, PP_HTONL(0x00000001UL)}};
82 const ip6_addr_t ip6_addr_allnodes_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x00000001UL)}};
83 const ip6_addr_t ip6_addr_allrpl_nodes_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x0000001aUL)}};
84 const ip6_addr_t ip6_addr_mpl_ip4_bcast = {{PP_HTONL(0xff130000UL), 0, 0, PP_HTONL(0x000000fcUL)}};
85 const ip6_addr_t ip6_addr_allrouters_linklocal = {{PP_HTONL(0xff020000UL), 0, 0, PP_HTONL(0x00000002UL)}};
86 #endif
87 void
ip6_addr_set_fun(ip6_addr_t * dest,ip6_addr_t * src)88 ip6_addr_set_fun(ip6_addr_t *dest, ip6_addr_t *src)
89 {
90 int i;
91 if (dest == NULL) {
92 return;
93 }
94 for (i = 0; i < IP6_ADDR_U32_ARR_SIZE; i++) {
95 dest->addr[i] = (src == NULL) ? 0 : src->addr[i];
96 }
97 ip6_addr_set_zone((dest), (src) == NULL ? IP6_NO_ZONE : ip6_addr_zone(src));
98 }
99 #endif
100
101 /**
102 * Check whether "cp" is a valid ascii representation
103 * of an IPv6 address and convert to a binary address.
104 * Returns 1 if the address is valid, 0 if not.
105 *
106 * @param cp IPv6 address in ascii representation (e.g. "FF01::1")
107 * @param addr pointer to which to save the ip address in network order
108 * @return 1 if cp could be converted to addr, 0 on failure
109 */
110 int
ip6addr_aton(const char * cp,ip6_addr_t * addr)111 ip6addr_aton(const char *cp, ip6_addr_t *addr)
112 {
113 u32_t addr_index, zero_blocks, current_block_index, current_block_value;
114 const char *s;
115 #if LWIP_IPV4
116 int check_ipv4_mapped = 0;
117 #endif /* LWIP_IPV4 */
118
119 LWIP_ERROR("inet_ntop:src is NULL", (cp != NULL), return 0);
120 u8_t max_colon = 0;
121 for (s = cp; *s != 0; s++) {
122 if (*s == ':') {
123 max_colon = max_colon + 1;
124 }
125 }
126 /* Count the number of colons, to count the number of blocks in a "::" sequence
127 zero_blocks may be 1 even if there are no :: sequences */
128 zero_blocks = 8;
129 u8_t count = 0;
130 u8_t current_colon = 1;
131 u8_t last_word = 0;
132 u8_t last_word_flag = 0;
133 for (s = cp; *s != 0; s++) {
134 count = count + 1;
135 if (last_word_flag > 0) {
136 last_word = last_word + 1;
137 if (last_word > IP6_ADDR_BLOCK_SIZE_MAX) {
138 return 0;
139 }
140 }
141 if (*s == ':') {
142 if (current_colon == max_colon) {
143 last_word_flag = 1;
144 }
145 current_colon = current_colon + 1;
146 if (count > (IP6_ADDR_BLOCK_SIZE_MAX + 1)) {
147 return 0;
148 }
149 count = 0;
150 zero_blocks--;
151 #if LWIP_IPV4
152 } else if (*s == '.') {
153 if ((zero_blocks == 6) || (zero_blocks == 5) || (zero_blocks == 2)) {
154 check_ipv4_mapped = 1;
155 /* last block could be the start of an IPv4 address */
156 zero_blocks--;
157 } else {
158 /* invalid format */
159 return 0;
160 }
161 break;
162 #endif /* LWIP_IPV4 */
163 } else if (!lwip_isxdigit(*s)) {
164 return 0;
165 }
166 }
167
168 /* parse each block */
169 addr_index = 0;
170 current_block_index = 0;
171 current_block_value = 0;
172 for (s = cp; *s != 0; s++) {
173 if (*s == ':') {
174 if (*(s + 1) == 0) {
175 return 0;
176 }
177 if (addr) {
178 if (current_block_index & 0x1) {
179 addr->addr[addr_index++] |= current_block_value;
180 }
181 else {
182 addr->addr[addr_index] = current_block_value << 16;
183 }
184 }
185 current_block_index++;
186 #if LWIP_IPV4
187 if ((check_ipv4_mapped != 0) && (current_block_index == 6)) {
188 ip4_addr_t ip4;
189 int ret = ip4addr_aton(s + 1, &ip4);
190 if (ret) {
191 if (addr) {
192 addr->addr[3] = lwip_htonl(ip4.addr);
193 current_block_index++;
194 goto fix_byte_order_and_return;
195 }
196 return 1;
197 }
198 }
199 #endif /* LWIP_IPV4 */
200 current_block_value = 0;
201 if (current_block_index > 7) {
202 /* address too long! */
203 return 0;
204 }
205 if (s[1] == ':') {
206 if (s[2] == ':') {
207 /* invalid format: three successive colons */
208 return 0;
209 }
210 s++;
211 /* "::" found, set zeros */
212 while (zero_blocks > 0) {
213 zero_blocks--;
214 if (current_block_index & 0x1) {
215 addr_index++;
216 } else {
217 if (addr) {
218 addr->addr[addr_index] = 0;
219 }
220 }
221 current_block_index++;
222 if (current_block_index > 7) {
223 /* address too long! */
224 return 0;
225 }
226 }
227 #if LWIP_IPV4
228 if (check_ipv4_mapped) {
229 /* IPv4-Compatible IPv6 address */
230 if (current_block_index == 6) {
231 ip4_addr_t ip4;
232 int ret = ip4addr_aton(s + 1, &ip4);
233 if (ret) {
234 if (addr != NULL) {
235 addr->addr[3] = lwip_htonl(ip4.addr);
236 current_block_index++;
237 goto fix_byte_order_and_return;
238 }
239 return 1;
240 }
241 }
242 }
243 #endif /* LWIP_IPV4 */
244 }
245 } else if (lwip_isxdigit(*s)) {
246 /* add current digit */
247 current_block_value = (current_block_value << 4) +
248 (lwip_isdigit(*s) ? (u32_t)(*s - '0') :
249 (u32_t)(10 + (lwip_islower(*s) ? *s - 'a' : *s - 'A')));
250 } else {
251 /* unexpected digit, space? CRLF? */
252 break;
253 }
254 }
255
256 if (addr) {
257 if (current_block_index & 0x1) {
258 addr->addr[addr_index++] |= current_block_value;
259 }
260 else {
261 addr->addr[addr_index] = current_block_value << 16;
262 }
263 #if LWIP_IPV4
264 fix_byte_order_and_return:
265 #endif
266 /* convert to network byte order. */
267 for (addr_index = 0; addr_index < 4; addr_index++) {
268 addr->addr[addr_index] = lwip_htonl(addr->addr[addr_index]);
269 }
270
271 ip6_addr_clear_zone(addr);
272 }
273
274 if (current_block_index != 7) {
275 return 0;
276 }
277
278 return 1;
279 }
280
281 /**
282 * Convert numeric IPv6 address into ASCII representation.
283 * returns ptr to static buffer; not reentrant!
284 *
285 * @param addr ip6 address in network order to convert
286 * @return pointer to a global static (!) buffer that holds the ASCII
287 * representation of addr
288 */
289 char *
ip6addr_ntoa(const ip6_addr_t * addr)290 ip6addr_ntoa(const ip6_addr_t *addr)
291 {
292 static char str[40];
293 LWIP_ERROR("inet_ntop:dst is NULL", (addr != NULL), return NULL);
294 return ip6addr_ntoa_r(addr, str, 40);
295 }
296
297 /**
298 * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
299 *
300 * @param addr ip6 address in network order to convert
301 * @param buf target buffer where the string is stored
302 * @param buflen length of buf
303 * @return either pointer to buf which now holds the ASCII
304 * representation of addr or NULL if buf was too small
305 */
306 char *
ip6addr_ntoa_r(const ip6_addr_t * addr,char * buf,int buflen)307 ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
308 {
309 u32_t current_block_index, current_block_value, next_block_value;
310 s32_t i;
311 u8_t zero_flag, empty_block_flag;
312 #if LWIP_IPV4
313 ip4_addr_t addr4;
314 char *ret = NULL;
315 char *buf_ip4 = NULL;
316 int buflen_ip4;
317 #endif
318
319 if ((addr == NULL) || (buf == NULL)) {
320 set_errno(ENOSPC);
321 return NULL;
322 }
323
324 #if LWIP_IPV4
325 /**
326 * @page RFC-6052 RFC-6052
327 * @par RFC-6052 Compliance Information
328 * @par Compliant Section
329 * Section 2. IPv4-Embedded IPv6 Address Prefix and Format
330 * @par Behavior Description
331 * IPv4-converted IPv6 addresses and IPv4-translatable IPv6 addresses
332 * follow the same format, described here as the IPv4-embedded IPv6
333 * address Format. \n
334 * @verbatim
335 * +-------------------+--------------+----------------------------+
336 * | Well-Known Prefix | IPv4 address | IPv4-Embedded IPv6 address |
337 * +-------------------+--------------+----------------------------+
338 * | 64:ff9b::/96 | 192.0.2.33 | 64:ff9b::192.0.2.33 |
339 * +-------------------+--------------+----------------------------+
340 * @endverbatim
341 */
342 /**
343 * @page RFC-4291 RFC-4291
344 * @par RFC-4291 Compliance Information
345 * @par Compliant Sections
346 * Section 2.5.5. IPv6 Addresses with Embedded IPv4 Addresses
347 * @par Behavior Description
348 * Two types of IPv6 addresses are defined that carry an IPv4 address in
349 * the low-order 32 bits of the address. These are the "IPv4-Compatible
350 * IPv6 address" and the "IPv4-mapped IPv6 address".
351 */
352 if (ip6_addr_isipv4mappedipv6(addr) || ip6_addr_isipv4compatible(addr)) {
353 char *header = NULL;
354 size_t header_len;
355
356 if (ip6_addr_isipv4mappedipv6(addr)) {
357 header = IP4MAPPED_HEADER;
358 header_len = sizeof(IP4MAPPED_HEADER);
359 } else {
360 header = IPV4COMPATIBLE_HEADER;
361 header_len = sizeof(IPV4COMPATIBLE_HEADER);
362 }
363
364 /* check buffer len before incrementing the buffer */
365 if (buflen < (int)header_len) {
366 return NULL;
367 }
368
369 /* Dual-stack: This is an IPv4 mapped address */
370 buf_ip4 = buf + header_len - 1;
371 buflen_ip4 = (int)((unsigned int)buflen - header_len + 1);
372
373 if (memcpy_s(buf, (size_t)buflen, header, header_len) != EOK) {
374 return NULL;
375 }
376
377 addr4.addr = addr->addr[3];
378 ret = ip4addr_ntoa_r(&addr4, buf_ip4, buflen_ip4);
379 if (ret != buf_ip4) {
380 return NULL;
381 }
382 return buf;
383 }
384 #endif /* LWIP_IPV4 */
385 i = 0;
386 empty_block_flag = 0; /* used to indicate a zero chain for "::' */
387
388 for (current_block_index = 0; current_block_index < 8; current_block_index++) {
389 /* get the current 16-bit block */
390 current_block_value = lwip_htonl(addr->addr[current_block_index >> 1]);
391 if ((current_block_index & 0x1) == 0) {
392 current_block_value = current_block_value >> 16;
393 }
394 current_block_value &= 0xffff;
395
396 /* Check for empty block. */
397 if (current_block_value == 0) {
398 if ((current_block_index == 7) && (empty_block_flag != 2)) {
399 /* special case, we must render a ':' for the last block. */
400 buf[i++] = ':';
401 if (i >= buflen) {
402 return NULL;
403 }
404 if (empty_block_flag == 0) {
405 /* Check whether the starting of the zero block is the last block(16 bits) in the representation */
406 /* In that case, we have to render ":0" to the output string and exit */
407 buf[i++] = '0';
408 if (i >= buflen) {
409 return NULL;
410 }
411 }
412 break;
413 }
414 if (empty_block_flag == 0) {
415 /* generate empty block "::", but only if more than one contiguous zero block,
416 * according to current formatting suggestions RFC 5952. */
417 next_block_value = lwip_htonl(addr->addr[(current_block_index + 1) >> 1]);
418 if ((current_block_index & 0x1) == 0x01) {
419 next_block_value = next_block_value >> 16;
420 }
421 next_block_value &= 0xffff;
422 if (next_block_value == 0) {
423 empty_block_flag = 1;
424 buf[i++] = ':';
425 if (i >= buflen) {
426 return NULL;
427 }
428 /* If the current_block_index is the last block and last block empty then, add '0' */
429 if (current_block_index == 7) {
430 buf[i++] = (char)(lwip_xchar((char)(current_block_value & 0xf)));
431 }
432 if (i >= buflen) {
433 return NULL;
434 }
435 continue; /* move on to next block. */
436 }
437 } else if (empty_block_flag == 1) {
438 /* move on to next block. */
439 continue;
440 }
441 } else if (empty_block_flag == 1) {
442 /* Set this flag value so we don't produce multiple empty blocks. */
443 empty_block_flag = 2;
444 }
445
446 if (current_block_index > 0) {
447 buf[i++] = ':';
448 if (i >= buflen) {
449 return NULL;
450 }
451 }
452
453 if ((current_block_value & 0xf000) == 0) {
454 zero_flag = 1;
455 } else {
456 buf[i++] = lwip_xchar(((current_block_value & 0xf000) >> 12));
457 zero_flag = 0;
458 if (i >= buflen) {
459 return NULL;
460 }
461 }
462
463 if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
464 /* do nothing */
465 } else {
466 buf[i++] = lwip_xchar(((current_block_value & 0xf00) >> 8));
467 zero_flag = 0;
468 if (i >= buflen) {
469 return NULL;
470 }
471 }
472
473 if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
474 /* do nothing */
475 }
476 else {
477 buf[i++] = lwip_xchar(((current_block_value & 0xf0) >> 4));
478 zero_flag = 0;
479 if (i >= buflen) {
480 return NULL;
481 }
482 }
483
484 buf[i++] = lwip_xchar((current_block_value & 0xf));
485 if (i >= buflen) {
486 return NULL;
487 }
488 }
489
490 buf[i] = 0;
491
492 return buf;
493 }
494
495 #endif /* LWIP_IPV6 */
496