Coverage Report

Created: 2025-05-04 06:22

/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