]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mdns_objects/mdns_address.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mdns_objects / mdns_address.c
1 /*
2 * Copyright (c) 2019 Apple Inc. All rights reserved.
3 *
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
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #include "mdns_address.h"
18
19 #include "mdns_helpers.h"
20 #include "mdns_internal.h"
21 #include "mdns_objects.h"
22
23 #include <CoreUtils/CoreUtils.h>
24
25 //======================================================================================================================
26 // MARK: - Address Kind Definition
27
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.
32 };
33
34 MDNS_OBJECT_SUBKIND_DEFINE_FULL(address);
35
36 //======================================================================================================================
37 // MARK: - Internals
38
39 MDNS_LOG_CATEGORY_DEFINE(address, "address");
40
41 //======================================================================================================================
42 // MARK: - Address Public Methods
43
44 mdns_address_t
45 mdns_address_create_ipv4(uint32_t addr, uint16_t port)
46 {
47 mdns_address_t obj = _mdns_address_alloc();
48 require_quiet(obj, exit);
49
50 struct sockaddr_in * const sa = &obj->sip.v4;
51 SIN_LEN_SET(sa);
52 sa->sin_family = AF_INET;
53 sa->sin_port = htons(port);
54 sa->sin_addr.s_addr = htonl(addr);
55
56 exit:
57 return obj;
58 }
59
60 //======================================================================================================================
61
62 mdns_address_t
63 mdns_address_create_ipv6(const uint8_t addr[static 16], uint16_t port, uint32_t scope_id)
64 {
65 mdns_address_t obj = _mdns_address_alloc();
66 require_quiet(obj, exit);
67
68 struct sockaddr_in6 * const sa = &obj->sip.v6;
69 SIN6_LEN_SET(sa);
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);
78 if (!name_err) {
79 obj->if_name = strdup(name_ptr);
80 } else {
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));
83 }
84 }
85
86 exit:
87 return obj;
88 }
89
90 //======================================================================================================================
91
92 static OSStatus
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);
95
96 mdns_address_t
97 mdns_address_create_from_ip_address_string(const char *addr_str)
98 {
99 mdns_address_t address = NULL;
100 const char * port_str;
101 uint32_t scope_id;
102 uint8_t addr_bytes[16];
103 bool addr_is_ipv6;
104
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];
108
109 // Look for closing bracket.
110 const char *end_bracket = strchr(ptr, ']');
111 require_quiet(end_bracket, exit);
112
113 const OSStatus err = _mdns_address_parse_ipv6(ptr, end_bracket, addr_bytes, &scope_id);
114 require_noerr_quiet(err, exit);
115
116 // Check for a port delimiter immediately after the closing bracket.
117 ptr = end_bracket + 1;
118 if (*ptr == ':') {
119 port_str = ++ptr;
120 } else {
121 require_quiet(*ptr == '\0', exit);
122 port_str = NULL;
123 }
124 addr_is_ipv6 = true;
125 } else {
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);
128 if (!err) {
129 port_str = NULL;
130 addr_is_ipv6 = true;
131 } else {
132 const char *addr_ptr;
133 char addr_buf[128];
134
135 // Look for port delimiter.
136 const char *delim = strchr(addr_str, ':');
137 if (delim) {
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);
141
142 memcpy(addr_buf, addr_str, addr_len);
143 addr_buf[addr_len] = '\0';
144 addr_ptr = addr_buf;
145 port_str = ++delim;
146 } else {
147 addr_ptr = addr_str;
148 port_str = NULL;
149 }
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;
154 }
155 }
156 // If there's a port substring, convert it to its numerical value.
157 uint32_t port = 0;
158 if (port_str) {
159 require_quiet(*port_str != '\0', exit);
160 const char *ptr;
161 for (ptr = port_str; isdigit_safe(*ptr); ++ptr) {
162 const int c = *ptr;
163 port = (10 * port) + (uint32_t)(c - '0');
164 require_quiet(port <= UINT16_MAX, exit);
165 }
166 require_quiet(*ptr == '\0', exit);
167 }
168 if (addr_is_ipv6) {
169 address = mdns_address_create_ipv6(addr_bytes, (uint16_t)port, scope_id);
170 } else {
171 const uint32_t ipv4 = ReadBig32(addr_bytes);
172 address = mdns_address_create_ipv4(ipv4, (uint16_t)port);
173 }
174
175 exit:
176 return address;
177 }
178
179 static OSStatus
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)
182 {
183 OSStatus err;
184 if (!end) {
185 end = start;
186 while (*end != '\0') {
187 ++end;
188 }
189 }
190 // Look for zone separator.
191 const char *ptr = start;
192 while ((ptr < end) && (*ptr != '%')) {
193 ++ptr;
194 }
195 const char * const zone_separator = (ptr < end) ? ptr : NULL;
196
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);
200 char addr_buf[128];
201 require_action_quiet(addr_len < sizeof(addr_buf), exit, err = kMalformedErr);
202
203 memcpy(addr_buf, start, addr_len);
204 addr_buf[addr_len] = '\0';
205
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);
210
211 uint32_t scope_id;
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];
217
218 char *name_ptr;
219 if (zone_id_len < sizeof(name_buf)) {
220 name_ptr = name_buf;
221 } else {
222 name_mem = malloc(zone_id_len + 1);
223 require_action_quiet(name_mem, exit, err = kNoMemoryErr);
224 name_ptr = name_mem;
225 }
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);
230 if (scope_id == 0) {
231 uint64_t u64 = 0;
232 for (ptr = zone_id; (ptr < end) && isdigit_safe(*ptr); ++ptr) {
233 const int c = *ptr;
234 u64 = (10 * u64) + (uint32_t)(c - '0');
235 require_action_quiet(u64 <= UINT32_MAX, exit, err = kMalformedErr);
236 }
237 require_action_quiet((ptr == end) && (ptr != zone_id), exit, err = kMalformedErr);
238
239 scope_id = (uint32_t)u64;
240 }
241 } else {
242 scope_id = 0;
243 }
244 if (out_addr_bytes) {
245 memcpy(out_addr_bytes, addr_bytes, 16);
246 }
247 if (out_scope_id) {
248 *out_scope_id = scope_id;
249 }
250 err = kNoErr;
251
252 exit:
253 return err;
254 }
255
256 //======================================================================================================================
257
258 const struct sockaddr *
259 mdns_address_get_sockaddr(mdns_address_t me)
260 {
261 return &me->sip.sa;
262 }
263
264 //======================================================================================================================
265
266 uint16_t
267 mdns_address_get_port(const mdns_address_t me)
268 {
269 switch (me->sip.sa.sa_family) {
270 case AF_INET:
271 return ntohs(me->sip.v4.sin_port);
272
273 case AF_INET6:
274 return ntohs(me->sip.v6.sin6_port);
275
276 default:
277 return 0;
278 }
279 }
280
281 //======================================================================================================================
282 // MARK: - Address Private Methods
283
284 static char *
285 _mdns_address_copy_description(mdns_address_t me, const bool debug, const bool privacy)
286 {
287 char * description = NULL;
288 char buffer[128];
289 char * dst = buffer;
290 const char * const lim = &buffer[countof(buffer)];
291 int n;
292
293 *dst = '\0';
294 if (debug) {
295 n = mdns_snprintf_add(&dst, lim, "<%s: %p>: ", me->base.kind->name, me);
296 require_quiet(n >= 0, exit);
297 }
298 switch (me->sip.sa.sa_family) {
299 case AF_INET: {
300 const struct sockaddr_in * const sa = &me->sip.v4;
301 const char *addr_str;
302 char addr_buf[INET_ADDRSTRLEN];
303
304 if (privacy) {
305 addr_str = "<REDACTED IPv4 ADDRESS>";
306 } else {
307 addr_str = inet_ntop(AF_INET, &sa->sin_addr.s_addr, addr_buf, (socklen_t)sizeof(addr_buf));
308 }
309 n = mdns_snprintf_add(&dst, lim, "%s", addr_str);
310 require_quiet(n >= 0, exit);
311
312 const int port = ntohs(sa->sin_port);
313 if (port != 0) {
314 n = mdns_snprintf_add(&dst, lim, ":%d", port);
315 require_quiet(n >= 0, exit);
316 }
317 break;
318 }
319 case AF_INET6: {
320 const struct sockaddr_in6 * const sa = &me->sip.v6;
321 const char *addr_str;
322 char addr_buf[INET6_ADDRSTRLEN];
323
324 if (privacy) {
325 addr_str = "<REDACTED IPv6 ADDRESS>";
326 } else {
327 addr_str = inet_ntop(AF_INET6, sa->sin6_addr.s6_addr, addr_buf, (socklen_t)sizeof(addr_buf));
328 }
329 const int port = ntohs(sa->sin6_port);
330 if (port != 0) {
331 n = mdns_snprintf_add(&dst, lim, "[");
332 require_quiet(n >= 0, exit);
333 }
334 n = mdns_snprintf_add(&dst, lim, "%s", addr_str);
335 require_quiet(n >= 0, exit);
336
337 if (sa->sin6_scope_id != 0) {
338 if (me->if_name) {
339 n = mdns_snprintf_add(&dst, lim, "%%%s", me->if_name);
340 require_quiet(n >= 0, exit);
341 } else {
342 n = mdns_snprintf_add(&dst, lim, "%%%u", sa->sin6_scope_id);
343 require_quiet(n >= 0, exit);
344 }
345 }
346 if (port != 0) {
347 n = mdns_snprintf_add(&dst, lim, "]:%d", port);
348 require_quiet(n >= 0, exit);
349 }
350 break;
351 }
352 default:
353 n = mdns_snprintf_add(&dst, lim, "<INVALID ADDRESS TYPE>");
354 require_quiet(n >= 0, exit);
355 break;
356 }
357 description = strdup(buffer);
358
359 exit:
360 return description;
361 }
362
363 //======================================================================================================================
364
365 static bool
366 _mdns_address_equal(mdns_address_t me, mdns_address_t other)
367 {
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)) {
375 return true;
376 }
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)) {
382 return true;
383 }
384 }
385 }
386 return false;
387 }
388
389 //======================================================================================================================
390
391 static void
392 _mdns_address_finalize(__unused mdns_address_t me)
393 {
394 ForgetMem(&me->if_name);
395 }