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 : #include <algorithm>
27 : #include <limits>
28 : #include <stdint.h>
29 : #include <stdio.h>
30 : #include <string.h>
31 :
32 : #include <inet/IPAddress.h>
33 : #include <inet/InetInterface.h>
34 : #include <lib/support/CodeUtils.h>
35 : #include <lib/support/StringBuilder.h>
36 :
37 : #if CHIP_SYSTEM_CONFIG_USE_POSIX_SOCKETS
38 : #include <arpa/inet.h>
39 : #endif
40 :
41 : namespace chip {
42 : namespace Inet {
43 :
44 : // Normalize a string to lowercase per RFC 5952 (canonical IPv6 text form).
45 : // ip6addr_ntoa_r and otIp6AddressToString output uppercase, which is
46 : // non-canonical.
47 2 : static void NormalizeIp6ToLower(char * str)
48 : {
49 52 : for (char * p = str; *p != '\0'; ++p)
50 : {
51 50 : if (*p >= 'A' && *p <= 'F')
52 : {
53 0 : *p = static_cast<char>(*p + ('a' - 'A'));
54 : }
55 : }
56 2 : }
57 :
58 15497 : char * IPAddress::ToString(char * buf, uint32_t bufSize) const
59 : {
60 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
61 : #if INET_CONFIG_ENABLE_IPV4
62 : if (IsIPv4())
63 : {
64 : ip4_addr_t ip4_addr = ToIPv4();
65 : ip4addr_ntoa_r(&ip4_addr, buf, (int) bufSize);
66 : }
67 : else
68 : #endif // INET_CONFIG_ENABLE_IPV4
69 : {
70 : ip6_addr_t ip6_addr = ToIPv6();
71 : ip6addr_ntoa_r(&ip6_addr, buf, (int) bufSize);
72 : // Normalize to lowercase per RFC 5952 (canonical IPv6 text form).
73 : NormalizeIp6ToLower(buf);
74 : }
75 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
76 : // socklen_t is sometimes signed, sometimes not, so the only safe way to do
77 : // this is to promote everything to an unsigned type that's known to be big
78 : // enough for everything, then cast back to uint32_t after taking the min.
79 15497 : bufSize = static_cast<uint32_t>(
80 15497 : std::min(static_cast<uintmax_t>(std::numeric_limits<socklen_t>::max()), static_cast<uintmax_t>(bufSize)));
81 : #if INET_CONFIG_ENABLE_IPV4
82 15497 : if (IsIPv4())
83 : {
84 137 : const void * addr = &Addr[3];
85 137 : const char * s = inet_ntop(AF_INET, addr, buf, static_cast<socklen_t>(bufSize));
86 : // This cast is safe because |s| points into |buf| which is not const.
87 137 : buf = const_cast<char *>(s);
88 : }
89 : else
90 : #endif // INET_CONFIG_ENABLE_IPV4
91 : {
92 15360 : const void * addr = &Addr[0];
93 15360 : const char * s = inet_ntop(AF_INET6, addr, buf, static_cast<socklen_t>(bufSize));
94 : // This cast is safe because |s| points into |buf| which is not const.
95 15360 : buf = const_cast<char *>(s);
96 : }
97 : #elif CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
98 : otIp6Address addr = ToIPv6();
99 : otIp6AddressToString(&addr, buf, static_cast<uint16_t>(bufSize));
100 : // Normalize to lowercase per RFC 5952 (canonical IPv6 text form).
101 : NormalizeIp6ToLower(buf);
102 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
103 :
104 15497 : return buf;
105 : }
106 :
107 5 : char * IPAddress::ToString(char * buf, uint32_t bufSize, const Inet::InterfaceId & interfaceId) const
108 : {
109 5 : if (IsIPv6LinkLocal() && interfaceId.IsPresent())
110 : {
111 : char ipStr[IPAddress::kMaxStringLength];
112 2 : if (ToString(ipStr, sizeof(ipStr)) == nullptr)
113 : {
114 0 : return nullptr;
115 : }
116 :
117 : // Normalize to lowercase per RFC 5952 (canonical IPv6 text form).
118 2 : NormalizeIp6ToLower(ipStr);
119 :
120 2 : StringBuilderBase builder(buf, bufSize);
121 2 : builder.Add(ipStr);
122 :
123 : char ifName[Inet::InterfaceId::kMaxIfNameLength];
124 4 : if (interfaceId.GetInterfaceName(ifName, sizeof(ifName)) == CHIP_NO_ERROR)
125 : {
126 2 : builder.Add("%").Add(ifName);
127 : }
128 :
129 2 : return builder.Fit() ? buf : nullptr;
130 : }
131 :
132 3 : return ToString(buf, bufSize);
133 : }
134 :
135 1813 : bool IPAddress::FromString(const char * str, IPAddress & output)
136 : {
137 : #if INET_CONFIG_ENABLE_IPV4
138 1813 : if (strchr(str, ':') == nullptr)
139 : {
140 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
141 : ip4_addr_t ipv4Addr;
142 : if (!ip4addr_aton(str, &ipv4Addr))
143 : return false;
144 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
145 : struct in_addr ipv4Addr;
146 409 : if (inet_pton(AF_INET, str, &ipv4Addr) < 1)
147 0 : return false;
148 : #endif // !CHIP_SYSTEM_CONFIG_USE_LWIP
149 409 : output = IPAddress(ipv4Addr);
150 : }
151 : else
152 : #endif // INET_CONFIG_ENABLE_IPV4
153 : {
154 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
155 : ip6_addr_t ipv6Addr;
156 : if (!ip6addr_aton(str, &ipv6Addr))
157 : return false;
158 : #elif CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
159 : struct in6_addr ipv6Addr;
160 1404 : if (inet_pton(AF_INET6, str, &ipv6Addr) < 1)
161 0 : return false;
162 : #elif CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT
163 : otIp6Address ipv6Addr;
164 : if (OT_ERROR_NONE != otIp6AddressFromString(str, &ipv6Addr))
165 : return false;
166 : #endif
167 1404 : output = IPAddress(ipv6Addr);
168 : }
169 :
170 1813 : return true;
171 : }
172 :
173 55 : bool IPAddress::FromString(const char * str, size_t strLen, IPAddress & output)
174 : {
175 55 : bool res = false;
176 :
177 55 : if (strLen < INET6_ADDRSTRLEN)
178 : {
179 : char hostNameBuf[INET6_ADDRSTRLEN];
180 55 : memcpy(hostNameBuf, str, strLen);
181 55 : hostNameBuf[strLen] = 0;
182 55 : res = IPAddress::FromString(hostNameBuf, output);
183 : }
184 :
185 55 : return res;
186 : }
187 :
188 0 : bool IPAddress::FromString(const char * str, IPAddress & addrOutput, class InterfaceId & ifaceOutput)
189 : {
190 0 : char * addrStr = const_cast<char *>(str);
191 0 : char * addrPart = nullptr;
192 0 : char * scopePart = nullptr;
193 0 : char * strtokContext = nullptr;
194 :
195 0 : addrPart = strtok_r(addrStr, "%", &strtokContext);
196 0 : if (addrPart != nullptr)
197 : {
198 0 : scopePart = strtok_r(nullptr, "%", &strtokContext);
199 : }
200 :
201 0 : if (addrPart == nullptr || scopePart == nullptr)
202 : {
203 0 : ifaceOutput = Inet::InterfaceId();
204 0 : return Inet::IPAddress::FromString(addrStr, addrOutput);
205 : }
206 :
207 0 : CHIP_ERROR err = Inet::InterfaceId::InterfaceNameToId(scopePart, ifaceOutput);
208 0 : if (err != CHIP_NO_ERROR)
209 : {
210 0 : return false;
211 : }
212 0 : return Inet::IPAddress::FromString(addrPart, addrOutput);
213 : }
214 :
215 : } // namespace Inet
216 : } // namespace chip
|