• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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