/src/openweave-core/src/inet/InetUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2013-2017 Nest Labs, Inc. |
4 | | * All rights reserved. |
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 methods for parsing host names or IP |
22 | | * addresses and an optional port number and/or an optional |
23 | | * interface name from a human-readable string. |
24 | | * |
25 | | */ |
26 | | |
27 | | #include <string.h> |
28 | | |
29 | | #include <Weave/Support/NLDLLUtil.h> |
30 | | |
31 | | #include <InetLayer/InetLayer.h> |
32 | | |
33 | | namespace nl { |
34 | | namespace Inet { |
35 | | |
36 | | /** |
37 | | * Parse a human-readable string containing a host or IP address and |
38 | | * an optional port number (separated by a ':'), supporting the |
39 | | * following formats: |
40 | | * |
41 | | * * <host-name> |
42 | | * * <host-name>:<port> |
43 | | * * <ip-4-addr> |
44 | | * * <ip-4-addr>:<port> |
45 | | * * <ip-6-addr> |
46 | | * * [<ip-6-addr>]:<port> |
47 | | * |
48 | | * @param[in] aString The human-reable string to parse. |
49 | | * |
50 | | * @param[in] aStringLen The length, in characters, of aString. |
51 | | * |
52 | | * @param[out] aHost A pointer to the host name portion of the parsed |
53 | | * string. |
54 | | * |
55 | | * @param[out] aHostLen The length, in characters, of aHost. |
56 | | * |
57 | | * @param[out] aPort The port number, if present and successfully |
58 | | * parsed; otherwise, 0. |
59 | | * |
60 | | * @return #INET_ERROR_INVALID_HOST_NAME If the input to be parsed is of |
61 | | * zero-length or otherwise |
62 | | * malformed. |
63 | | * @return #INET_ERROR_HOST_NAME_TOO_LONG If the host name exceeds 253 |
64 | | * characters. |
65 | | * @return #INET_NO_ERROR On success. |
66 | | * |
67 | | */ |
68 | | NL_DLL_EXPORT INET_ERROR ParseHostAndPort(const char *aString, uint16_t aStringLen, const char *&aHost, uint16_t &aHostLen, uint16_t &aPort) |
69 | 0 | { |
70 | 0 | const char *end = aString + aStringLen; |
71 | 0 | const char *p; |
72 | |
|
73 | 0 | if (aStringLen == 0) |
74 | 0 | return INET_ERROR_INVALID_HOST_NAME; |
75 | | |
76 | | // If the string starts with a [ then it is a backeted |
77 | | // host/address, possibly with a port number following it. |
78 | | |
79 | 0 | if (*aString == '[') |
80 | 0 | { |
81 | | // Search for the end bracket. |
82 | 0 | p = (const char *)memchr(aString, ']', aStringLen); |
83 | 0 | if (p == NULL) |
84 | 0 | return INET_ERROR_INVALID_HOST_NAME; |
85 | | |
86 | | // Return the IPv6 address. |
87 | 0 | aHost = aString + 1; |
88 | 0 | aHostLen = p - aHost; |
89 | | |
90 | | // Skip the end bracket. |
91 | 0 | p++; |
92 | 0 | } |
93 | | |
94 | | // Otherwise, not a bracketed IPv6 address... |
95 | 0 | else |
96 | 0 | { |
97 | | // Search for a colon. |
98 | 0 | p = (const char *)memchr(aString, ':', aStringLen); |
99 | | |
100 | | // If the string contains no colons, then it is a host name or |
101 | | // IPv4 address without a port. |
102 | | // |
103 | | // If the string contains MULTIPLE colons, then it is an IPv6 |
104 | | // address without a port. |
105 | 0 | if (p == NULL || memchr(p + 1, ':', end - p - 1) != NULL) |
106 | 0 | p = end; |
107 | | |
108 | | // Return the host/address portion. |
109 | 0 | aHost = aString; |
110 | 0 | aHostLen = p - aString; |
111 | 0 | } |
112 | | |
113 | | // Enforce the DNS limit on the maximum length of a host name. |
114 | 0 | if (aHostLen > 253) |
115 | 0 | return INET_ERROR_HOST_NAME_TOO_LONG; |
116 | | |
117 | | // If there are more characters after the host name... |
118 | 0 | if (p < end) |
119 | 0 | { |
120 | | // Verify the presence of a colon. |
121 | 0 | if (*p++ != ':') |
122 | 0 | return INET_ERROR_INVALID_HOST_NAME; |
123 | | |
124 | | // Verify that the port number portion is not too long. |
125 | 0 | if ((end - p) > 5) |
126 | 0 | return INET_ERROR_INVALID_HOST_NAME; |
127 | | |
128 | | // Parse the port number. |
129 | 0 | aPort = 0; |
130 | 0 | for (; p < end; p++) |
131 | 0 | if (*p >= '0' && *p <= '9') |
132 | 0 | aPort = (aPort * 10) + (*p - '0'); |
133 | 0 | else |
134 | 0 | return INET_ERROR_INVALID_HOST_NAME; |
135 | 0 | } |
136 | | |
137 | | // Otherwise, tell the caller there was no port number. |
138 | 0 | else |
139 | 0 | aPort = 0; |
140 | | |
141 | 0 | return INET_NO_ERROR; |
142 | 0 | } |
143 | | |
144 | | /** |
145 | | * Parse a human-readable string containing a host or IP address, an |
146 | | * optional port number (separated by a ':'), and an optional |
147 | | * interface name (separated by a '%'), supporting the following |
148 | | * formats: |
149 | | * |
150 | | * * <host-name> |
151 | | * * <host-name>%<interface> |
152 | | * * <host-name>:<port> |
153 | | * * <host-name>:<port>%<interface> |
154 | | * * <ip-4-addr> |
155 | | * * <ip-4-addr>%<interface> |
156 | | * * <ip-4-addr>:<port> |
157 | | * * <ip-4-addr>:<port>%<interface> |
158 | | * * <ip-6-addr> |
159 | | * * <ip-6-addr>%<interface> |
160 | | * * [<ip-6-addr>]:<port> |
161 | | * * [<ip-6-addr>]:<port>%<interface> |
162 | | * |
163 | | * @param[in] aString The human-reable string to parse. |
164 | | * |
165 | | * @param[in] aStringLen The length, in characters, of aString. |
166 | | * |
167 | | * @param[out] aHost A pointer to the host name portion of the parsed |
168 | | * string. |
169 | | * |
170 | | * @param[out] aHostLen The length, in characters, of aHost. |
171 | | * |
172 | | * @param[out] aPort The port number, if present and successfully |
173 | | * parsed; otherwise, 0. |
174 | | * |
175 | | * @param[out] aInterface A pointer to the interface portion of the parsed |
176 | | * string. |
177 | | * |
178 | | * @param[out] aInterfaceLen The length, in characters, of aInterface. |
179 | | * |
180 | | * @return #INET_ERROR_INVALID_HOST_NAME If the input to be parsed is of |
181 | | * zero-length or otherwise |
182 | | * malformed. |
183 | | * @return #INET_ERROR_HOST_NAME_TOO_LONG If the host name exceeds 253 |
184 | | * characters. |
185 | | * @return #INET_NO_ERROR On success. |
186 | | * |
187 | | */ |
188 | | NL_DLL_EXPORT INET_ERROR ParseHostPortAndInterface(const char *aString, uint16_t aStringLen, |
189 | | const char *&aHost, uint16_t &aHostLen, |
190 | | uint16_t &aPort, |
191 | | const char *&aInterface, uint16_t &aInterfaceLen) |
192 | 0 | { |
193 | 0 | const char *end = aString + aStringLen; |
194 | |
|
195 | 0 | aInterface = NULL; |
196 | 0 | aInterfaceLen = 0; |
197 | |
|
198 | 0 | for (uint16_t i = 1; i < aStringLen; i++) |
199 | 0 | { |
200 | 0 | char ch = *(end - i); |
201 | 0 | if (ch == '%') |
202 | 0 | { |
203 | 0 | aInterface = end - i + 1; |
204 | 0 | aInterfaceLen = i - 1; |
205 | 0 | aStringLen -= i; |
206 | 0 | break; |
207 | 0 | } |
208 | 0 | if (ch == ':' || ch == ']') |
209 | 0 | break; |
210 | 0 | } |
211 | |
|
212 | 0 | return ParseHostAndPort(aString, aStringLen, aHost, aHostLen, aPort); |
213 | 0 | } |
214 | | |
215 | | } // namespace Inet |
216 | | } // namespace nl |