Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 :
19 : /**
20 : * @file
21 : * This file implements the human-readable string formatting and
22 : * parsing methods from class <tt>Inet::IPAddress</tt>.
23 : *
24 : */
25 :
26 : #ifndef __STDC_LIMIT_MACROS
27 : #define __STDC_LIMIT_MACROS
28 : #endif
29 : #include <limits>
30 : #include <stdint.h>
31 : #include <stdio.h>
32 : #include <string.h>
33 :
34 : #include <inet/IPAddress.h>
35 : #include <lib/support/CodeUtils.h>
36 :
37 : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
38 : #include <arpa/inet.h>
39 : #endif
40 :
41 : namespace chip {
42 : namespace Inet {
43 :
44 9796 : char * IPAddress::ToString(char * buf, uint32_t bufSize) const
45 : {
46 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
47 : #if INET_CONFIG_ENABLE_IPV4
48 : if (IsIPv4())
49 : {
50 : ip4_addr_t ip4_addr = ToIPv4();
51 : ip4addr_ntoa_r(&ip4_addr, buf, (int) bufSize);
52 : }
53 : else
54 : #endif // INET_CONFIG_ENABLE_IPV4
55 : {
56 : ip6_addr_t ip6_addr = ToIPv6();
57 : ip6addr_ntoa_r(&ip6_addr, buf, (int) bufSize);
58 : }
59 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS
60 : // socklen_t is sometimes signed, sometimes not, so the only safe way to do
61 : // this is to promote everything to an unsigned type that's known to be big
62 : // enough for everything, then cast back to uint32_t after taking the min.
63 9796 : bufSize =
64 9796 : static_cast<uint32_t>(min(static_cast<uintmax_t>(std::numeric_limits<socklen_t>::max()), static_cast<uintmax_t>(bufSize)));
65 : #if INET_CONFIG_ENABLE_IPV4
66 9796 : if (IsIPv4())
67 : {
68 89 : const void * addr = &Addr[3];
69 89 : const char * s = inet_ntop(AF_INET, addr, buf, static_cast<socklen_t>(bufSize));
70 : // This cast is safe because |s| points into |buf| which is not const.
71 89 : buf = const_cast<char *>(s);
72 : }
73 : else
74 : #endif // INET_CONFIG_ENABLE_IPV4
75 : {
76 9707 : const void * addr = &Addr[0];
77 9707 : const char * s = inet_ntop(AF_INET6, addr, buf, static_cast<socklen_t>(bufSize));
78 : // This cast is safe because |s| points into |buf| which is not const.
79 9707 : buf = const_cast<char *>(s);
80 : }
81 : #elif CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
82 : otIp6Address addr = ToIPv6();
83 : otIp6AddressToString(&addr, buf, static_cast<uint16_t>(bufSize));
84 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
85 :
86 9796 : return buf;
87 : }
88 :
89 523 : bool IPAddress::FromString(const char * str, IPAddress & output)
90 : {
91 : #if INET_CONFIG_ENABLE_IPV4
92 523 : if (strchr(str, ':') == nullptr)
93 : {
94 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
95 : ip4_addr_t ipv4Addr;
96 : if (!ip4addr_aton(str, &ipv4Addr))
97 : return false;
98 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS
99 : struct in_addr ipv4Addr;
100 224 : if (inet_pton(AF_INET, str, &ipv4Addr) < 1)
101 0 : return false;
102 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
103 224 : output = IPAddress(ipv4Addr);
104 : }
105 : else
106 : #endif // INET_CONFIG_ENABLE_IPV4
107 : {
108 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
109 : ip6_addr_t ipv6Addr;
110 : if (!ip6addr_aton(str, &ipv6Addr))
111 : return false;
112 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS
113 : struct in6_addr ipv6Addr;
114 299 : if (inet_pton(AF_INET6, str, &ipv6Addr) < 1)
115 0 : return false;
116 : #elif CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
117 : otIp6Address ipv6Addr;
118 : if (OT_ERROR_NONE != otIp6AddressFromString(str, &ipv6Addr))
119 : return false;
120 : #endif
121 299 : output = IPAddress(ipv6Addr);
122 : }
123 :
124 523 : return true;
125 : }
126 :
127 55 : bool IPAddress::FromString(const char * str, size_t strLen, IPAddress & output)
128 : {
129 55 : bool res = false;
130 :
131 55 : if (strLen < INET6_ADDRSTRLEN)
132 : {
133 : char hostNameBuf[INET6_ADDRSTRLEN];
134 55 : memcpy(hostNameBuf, str, strLen);
135 55 : hostNameBuf[strLen] = 0;
136 55 : res = IPAddress::FromString(hostNameBuf, output);
137 : }
138 :
139 55 : return res;
140 : }
141 :
142 0 : bool IPAddress::FromString(const char * str, IPAddress & addrOutput, class InterfaceId & ifaceOutput)
143 : {
144 0 : char * addrStr = const_cast<char *>(str);
145 0 : char * addrPart = nullptr;
146 0 : char * scopePart = nullptr;
147 0 : char * strtokContext = nullptr;
148 :
149 0 : addrPart = strtok_r(addrStr, "%", &strtokContext);
150 0 : if (addrPart != nullptr)
151 : {
152 0 : scopePart = strtok_r(nullptr, "%", &strtokContext);
153 : }
154 :
155 0 : if (addrPart == nullptr || scopePart == nullptr)
156 : {
157 0 : ifaceOutput = Inet::InterfaceId();
158 0 : return Inet::IPAddress::FromString(addrStr, addrOutput);
159 : }
160 :
161 0 : CHIP_ERROR err = Inet::InterfaceId::InterfaceNameToId(scopePart, ifaceOutput);
162 0 : if (err != CHIP_NO_ERROR)
163 : {
164 0 : return false;
165 : }
166 0 : return Inet::IPAddress::FromString(addrPart, addrOutput);
167 : }
168 :
169 : } // namespace Inet
170 : } // namespace chip
|