2 * Copyright (c) 2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * https://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "mdns_address.h"
19 #include "mdns_helpers.h"
20 #include "mdns_internal.h"
21 #include "mdns_objects.h"
23 #include <CoreUtils/CoreUtils.h>
25 //======================================================================================================================
26 // MARK: - Address Kind Definition
28 struct mdns_address_s
{
29 struct mdns_object_s base
; // Object base.
30 sockaddr_ip sip
; // Underlying sockaddr structure.
31 char * if_name
; // Interface name of IPv6 scope ID.
34 MDNS_OBJECT_SUBKIND_DEFINE_FULL(address
);
36 //======================================================================================================================
39 MDNS_LOG_CATEGORY_DEFINE(address
, "address");
41 //======================================================================================================================
42 // MARK: - Address Public Methods
45 mdns_address_create_ipv4(uint32_t addr
, uint16_t port
)
47 mdns_address_t obj
= _mdns_address_alloc();
48 require_quiet(obj
, exit
);
50 struct sockaddr_in
* const sa
= &obj
->sip
.v4
;
52 sa
->sin_family
= AF_INET
;
53 sa
->sin_port
= htons(port
);
54 sa
->sin_addr
.s_addr
= htonl(addr
);
60 //======================================================================================================================
63 mdns_address_create_ipv6(const uint8_t addr
[static 16], uint16_t port
, uint32_t scope_id
)
65 mdns_address_t obj
= _mdns_address_alloc();
66 require_quiet(obj
, exit
);
68 struct sockaddr_in6
* const sa
= &obj
->sip
.v6
;
70 sa
->sin6_family
= AF_INET6
;
71 sa
->sin6_port
= htons(port
);
72 memcpy(sa
->sin6_addr
.s6_addr
, addr
, 16);
73 sa
->sin6_scope_id
= scope_id
;
74 if (sa
->sin6_scope_id
!= 0) {
75 char name_buf
[IF_NAMESIZE
+ 1];
76 const char *name_ptr
= if_indextoname(sa
->sin6_scope_id
, name_buf
);
77 const int name_err
= map_global_value_errno(name_ptr
, name_ptr
);
79 obj
->if_name
= strdup(name_ptr
);
81 os_log_error(_mdns_address_log(), "if_indextoname() for %u failed with error %d: %s",
82 sa
->sin6_scope_id
, name_err
, strerror(name_err
));
90 //======================================================================================================================
93 _mdns_address_parse_ipv6(const char * const start
, const char *end
, uint8_t out_addr_bytes
[16],
94 uint32_t * const out_scope_id
);
97 mdns_address_create_from_ip_address_string(const char *addr_str
)
99 mdns_address_t address
= NULL
;
100 const char * port_str
;
102 uint8_t addr_bytes
[16];
105 // An opening bracket implies an IPv6 address, e.g., "[<IPv6 address>]:<port>" or "[<IPv6 address>]".
106 if (*addr_str
== '[') {
107 const char *ptr
= &addr_str
[1];
109 // Look for closing bracket.
110 const char *end_bracket
= strchr(ptr
, ']');
111 require_quiet(end_bracket
, exit
);
113 const OSStatus err
= _mdns_address_parse_ipv6(ptr
, end_bracket
, addr_bytes
, &scope_id
);
114 require_noerr_quiet(err
, exit
);
116 // Check for a port delimiter immediately after the closing bracket.
117 ptr
= end_bracket
+ 1;
121 require_quiet(*ptr
== '\0', exit
);
126 // Try to parse the string as an IPv6 address.
127 const OSStatus err
= _mdns_address_parse_ipv6(addr_str
, NULL
, addr_bytes
, &scope_id
);
132 const char *addr_ptr
;
135 // Look for port delimiter.
136 const char *delim
= strchr(addr_str
, ':');
138 // Copy the substring up to the port delimiter.
139 const size_t addr_len
= (size_t)(delim
- addr_str
);
140 require_quiet(addr_len
< sizeof(addr_buf
), exit
);
142 memcpy(addr_buf
, addr_str
, addr_len
);
143 addr_buf
[addr_len
] = '\0';
150 // Try to parse the string or substring as an IPv4 address.
151 const int result
= inet_pton(AF_INET
, addr_ptr
, addr_bytes
);
152 require_quiet(result
== 1, exit
);
153 addr_is_ipv6
= false;
156 // If there's a port substring, convert it to its numerical value.
159 require_quiet(*port_str
!= '\0', exit
);
161 for (ptr
= port_str
; isdigit_safe(*ptr
); ++ptr
) {
163 port
= (10 * port
) + (uint32_t)(c
- '0');
164 require_quiet(port
<= UINT16_MAX
, exit
);
166 require_quiet(*ptr
== '\0', exit
);
169 address
= mdns_address_create_ipv6(addr_bytes
, (uint16_t)port
, scope_id
);
171 const uint32_t ipv4
= ReadBig32(addr_bytes
);
172 address
= mdns_address_create_ipv4(ipv4
, (uint16_t)port
);
180 _mdns_address_parse_ipv6(const char * const start
, const char *end
, uint8_t out_addr_bytes
[16],
181 uint32_t * const out_scope_id
)
186 while (*end
!= '\0') {
190 // Look for zone separator.
191 const char *ptr
= start
;
192 while ((ptr
< end
) && (*ptr
!= '%')) {
195 const char * const zone_separator
= (ptr
< end
) ? ptr
: NULL
;
197 // Copy substring enclosed in the brackets.
198 const char * const addr_lim
= zone_separator
? zone_separator
: end
;
199 const size_t addr_len
= (size_t)(addr_lim
- start
);
201 require_action_quiet(addr_len
< sizeof(addr_buf
), exit
, err
= kMalformedErr
);
203 memcpy(addr_buf
, start
, addr_len
);
204 addr_buf
[addr_len
] = '\0';
206 // Try to parse substring as an IPv6 address.
207 uint8_t addr_bytes
[16];
208 const int result
= inet_pton(AF_INET6
, addr_buf
, addr_bytes
);
209 require_action_quiet(result
== 1, exit
, err
= kMalformedErr
);
212 if (zone_separator
) {
213 const char * const zone_id
= zone_separator
+ 1;
214 const size_t zone_id_len
= (size_t)(end
- zone_id
);
215 char * name_mem
= NULL
;
216 char name_buf
[IF_NAMESIZE
+ 1];
219 if (zone_id_len
< sizeof(name_buf
)) {
222 name_mem
= malloc(zone_id_len
+ 1);
223 require_action_quiet(name_mem
, exit
, err
= kNoMemoryErr
);
226 memcpy(name_ptr
, zone_id
, zone_id_len
);
227 name_ptr
[zone_id_len
] = '\0';
228 scope_id
= if_nametoindex(name_ptr
);
229 ForgetMem(&name_mem
);
232 for (ptr
= zone_id
; (ptr
< end
) && isdigit_safe(*ptr
); ++ptr
) {
234 u64
= (10 * u64
) + (uint32_t)(c
- '0');
235 require_action_quiet(u64
<= UINT32_MAX
, exit
, err
= kMalformedErr
);
237 require_action_quiet((ptr
== end
) && (ptr
!= zone_id
), exit
, err
= kMalformedErr
);
239 scope_id
= (uint32_t)u64
;
244 if (out_addr_bytes
) {
245 memcpy(out_addr_bytes
, addr_bytes
, 16);
248 *out_scope_id
= scope_id
;
256 //======================================================================================================================
258 const struct sockaddr
*
259 mdns_address_get_sockaddr(mdns_address_t me
)
264 //======================================================================================================================
267 mdns_address_get_port(const mdns_address_t me
)
269 switch (me
->sip
.sa
.sa_family
) {
271 return ntohs(me
->sip
.v4
.sin_port
);
274 return ntohs(me
->sip
.v6
.sin6_port
);
281 //======================================================================================================================
282 // MARK: - Address Private Methods
285 _mdns_address_copy_description(mdns_address_t me
, const bool debug
, const bool privacy
)
287 char * description
= NULL
;
290 const char * const lim
= &buffer
[countof(buffer
)];
295 n
= mdns_snprintf_add(&dst
, lim
, "<%s: %p>: ", me
->base
.kind
->name
, me
);
296 require_quiet(n
>= 0, exit
);
298 switch (me
->sip
.sa
.sa_family
) {
300 const struct sockaddr_in
* const sa
= &me
->sip
.v4
;
301 const char *addr_str
;
302 char addr_buf
[INET_ADDRSTRLEN
];
305 addr_str
= "<REDACTED IPv4 ADDRESS>";
307 addr_str
= inet_ntop(AF_INET
, &sa
->sin_addr
.s_addr
, addr_buf
, (socklen_t
)sizeof(addr_buf
));
309 n
= mdns_snprintf_add(&dst
, lim
, "%s", addr_str
);
310 require_quiet(n
>= 0, exit
);
312 const int port
= ntohs(sa
->sin_port
);
314 n
= mdns_snprintf_add(&dst
, lim
, ":%d", port
);
315 require_quiet(n
>= 0, exit
);
320 const struct sockaddr_in6
* const sa
= &me
->sip
.v6
;
321 const char *addr_str
;
322 char addr_buf
[INET6_ADDRSTRLEN
];
325 addr_str
= "<REDACTED IPv6 ADDRESS>";
327 addr_str
= inet_ntop(AF_INET6
, sa
->sin6_addr
.s6_addr
, addr_buf
, (socklen_t
)sizeof(addr_buf
));
329 const int port
= ntohs(sa
->sin6_port
);
331 n
= mdns_snprintf_add(&dst
, lim
, "[");
332 require_quiet(n
>= 0, exit
);
334 n
= mdns_snprintf_add(&dst
, lim
, "%s", addr_str
);
335 require_quiet(n
>= 0, exit
);
337 if (sa
->sin6_scope_id
!= 0) {
339 n
= mdns_snprintf_add(&dst
, lim
, "%%%s", me
->if_name
);
340 require_quiet(n
>= 0, exit
);
342 n
= mdns_snprintf_add(&dst
, lim
, "%%%u", sa
->sin6_scope_id
);
343 require_quiet(n
>= 0, exit
);
347 n
= mdns_snprintf_add(&dst
, lim
, "]:%d", port
);
348 require_quiet(n
>= 0, exit
);
353 n
= mdns_snprintf_add(&dst
, lim
, "<INVALID ADDRESS TYPE>");
354 require_quiet(n
>= 0, exit
);
357 description
= strdup(buffer
);
363 //======================================================================================================================
366 _mdns_address_equal(mdns_address_t me
, mdns_address_t other
)
368 const int family
= me
->sip
.sa
.sa_family
;
369 if (family
== other
->sip
.sa
.sa_family
) {
370 if (family
== AF_INET
) {
371 const struct sockaddr_in
* const me_sa
= &me
->sip
.v4
;
372 const struct sockaddr_in
* const other_sa
= &other
->sip
.v4
;
373 if ((me_sa
->sin_port
== other_sa
->sin_port
) &&
374 (me_sa
->sin_addr
.s_addr
== other_sa
->sin_addr
.s_addr
)) {
377 } else if (family
== AF_INET6
) {
378 const struct sockaddr_in6
* const me_sa
= &me
->sip
.v6
;
379 const struct sockaddr_in6
* const other_sa
= &other
->sip
.v6
;
380 if ((me_sa
->sin6_port
== other_sa
->sin6_port
) &&
381 (memcmp(me_sa
->sin6_addr
.s6_addr
, other_sa
->sin6_addr
.s6_addr
, 16) == 0)) {
389 //======================================================================================================================
392 _mdns_address_finalize(__unused mdns_address_t me
)
394 ForgetMem(&me
->if_name
);