xref: /haiku/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 /*
2  * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Oliver Tappe, zooey@hirschkaefer.de
8  *		Atis Elsts, the.kfx@gmail.com
9  */
10 
11 
12 #include <net_datalink.h>
13 
14 #include <NetUtilities.h>
15 
16 #include <memory.h>
17 #include <netinet6/in6.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include "ipv6_address.h"
22 #include "ipv6_utils.h"
23 #include "jenkins.h"
24 
25 
26 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
27 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
28 
29 
30 static void
31 ipv6_mask_adress_inplace(sockaddr *address, const sockaddr *mask)
32 {
33 	in6_addr &i6addr = ((sockaddr_in6 *)address)->sin6_addr;
34 	const in6_addr &i6mask = ((const sockaddr_in6 *)mask)->sin6_addr;
35 
36 	for (uint32 i = 0; i < sizeof(in6_addr); i++)
37 		i6addr.s6_addr[i] &= i6mask.s6_addr[i];
38 }
39 
40 
41 /*!	Routing utility function: copies address \a from into a new address
42 	that is put into \a to.
43 	If \a replaceWithZeros is set \a from will be replaced by an empty
44 	address.
45 	If a \a mask is given it is applied to \a from (such that \a to is the
46 	result of \a from & \a mask).
47 	\return B_OK if the address could be copied
48 	\return B_NO_MEMORY if the new address could not be allocated
49 	\return B_BAD_VALUE if any of \a from or \a mask refers to an uninitialized
50 			address
51 	\return B_MISMATCHED_VALUES if \a address does not match family AF_INET
52 */
53 static status_t
54 ipv6_copy_address(const sockaddr *from, sockaddr **to,
55 	bool replaceWithZeros = false, const sockaddr *mask = NULL)
56 {
57 	if (replaceWithZeros) {
58 		*to = (sockaddr *)malloc(sizeof(sockaddr_in6));
59 		if (*to == NULL)
60 			return B_NO_MEMORY;
61 
62 		memset(*to, 0, sizeof(sockaddr_in6));
63 		(*to)->sa_family = AF_INET6;
64 		(*to)->sa_len = sizeof(sockaddr_in6);
65 	} else {
66 		if (from == NULL)
67 			return B_OK;
68 		if (from->sa_len == 0 || (mask != NULL && mask->sa_len == 0))
69 			return B_BAD_VALUE;
70 		if (from->sa_family != AF_INET6)
71 			return B_MISMATCHED_VALUES;
72 
73 		*to = (sockaddr *)malloc(sizeof(sockaddr_in6));
74 		if (*to == NULL)
75 			return B_NO_MEMORY;
76 
77 		memcpy(*to, from, sizeof(sockaddr_in6));
78 
79 		if (mask != NULL)
80 			ipv6_mask_adress_inplace(*to, mask);
81 	}
82 	return B_OK;
83 }
84 
85 
86 /*!	Routing utility function: applies \a mask to given \a address and puts
87 	the resulting address into \a result.
88 	\return B_OK if the mask has been applied
89 	\return B_BAD_VALUE if \a address is NULL or if any of \a address or \a mask
90 			refers to an uninitialized address
91 */
92 static status_t
93 ipv6_mask_address(const sockaddr *address, const sockaddr *mask,
94 	sockaddr *result)
95 {
96 	if (address == NULL || address->sa_len == 0 || result == NULL
97 			|| (mask != NULL && mask->sa_len == 0))
98 		return B_BAD_VALUE;
99 
100 	memcpy(result, address, sizeof(sockaddr_in6));
101 	if (mask != NULL)
102 		ipv6_mask_adress_inplace(result, mask);
103 
104 	return B_OK;
105 }
106 
107 
108 /*!	Checks if the given \a address is the empty address. By default, the port
109 	is checked, too, but you can avoid that by passing \a checkPort = false.
110 	\return true if \a address is NULL, uninitialized or the empty address,
111 		false if not
112 */
113 static bool
114 ipv6_is_empty_address(const sockaddr *_address, bool checkPort)
115 {
116 	if (_address == NULL || _address->sa_len == 0
117 		|| _address->sa_family == AF_UNSPEC)
118 		return true;
119 
120 	const sockaddr_in6 *address = (const sockaddr_in6 *)_address;
121 	if (checkPort && address->sin6_port != 0)
122 		return false;
123 
124 	return IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr);
125 }
126 
127 
128 /*!	Checks if the given \a address is an Ipv6 address.
129 	\return false if \a address is NULL, or with family different from AF_INET
130 		true if it has AF_INET address family
131 */
132 static bool
133 ipv6_is_same_family(const sockaddr *address)
134 {
135 	if (address == NULL)
136 		return false;
137 
138 	return address->sa_family == AF_INET6;
139 }
140 
141 
142 /*!	Compares the IP-addresses of the two given address structures \a a and \a b.
143 	\return true if IP-addresses of \a a and \a b are equal, false if not
144 */
145 static bool
146 ipv6_equal_addresses(const sockaddr *a, const sockaddr *b)
147 {
148 	if (a == NULL && b == NULL)
149 		return true;
150 	if (a != NULL && b == NULL)
151 		return ipv6_is_empty_address(a, false);
152 	if (a == NULL && b != NULL)
153 		return ipv6_is_empty_address(b, false);
154 
155 	const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
156 	const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
157 	return !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
158 }
159 
160 
161 /*!	Compares the ports of the two given address structures \a a and \a b.
162 	\return true if ports of \a a and \a b are equal, false if not
163 */
164 static bool
165 ipv6_equal_ports(const sockaddr *a, const sockaddr *b)
166 {
167 	uint16 portA = a ? ((sockaddr_in6 *)a)->sin6_port : 0;
168 	uint16 portB = b ? ((sockaddr_in6 *)b)->sin6_port : 0;
169 	return portA == portB;
170 }
171 
172 
173 /*!	Compares the IP-addresses and ports of the two given address structures
174 	\a a and \a b.
175 	\return true if IP-addresses and ports of \a a and \a b are equal, false if
176 			not
177 */
178 static bool
179 ipv6_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
180 {
181 	if (a == NULL && b == NULL)
182 		return true;
183 	if (a != NULL && b == NULL)
184 		return ipv6_is_empty_address(a, true);
185 	if (a == NULL && b != NULL)
186 		return ipv6_is_empty_address(b, true);
187 
188 	const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
189 	const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
190 	return i6a->sin6_port == i6b->sin6_port
191 		&& !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
192 }
193 
194 
195 /*!	Applies the given \a mask two \a a and \a b and then checks whether
196 	the masked addresses match.
197 	\return true if \a a matches \a b after masking both, false if not
198 */
199 static bool
200 ipv6_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
201 	const sockaddr *mask)
202 {
203 	if (a == NULL && b == NULL)
204 		return true;
205 
206 	const in6_addr *i6a;
207 	if (a == NULL)
208 		i6a = &in6addr_any;
209 	else
210 		i6a = &((const sockaddr_in6*)a)->sin6_addr;
211 
212 	const in6_addr *i6b;
213 	if (b == NULL)
214 		i6b = &in6addr_any;
215 	else
216 		i6b = &((const sockaddr_in6*)b)->sin6_addr;
217 
218  	if (!mask)
219 		return !memcmp(i6a, i6b, sizeof(in6_addr));
220 
221 	const uint8 *pmask = ((const sockaddr_in6 *)mask)->sin6_addr.s6_addr;
222 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
223 		if (pmask[i] != 0xff) {
224 			return (i6a->s6_addr[i] & pmask[i])
225 				== (i6b->s6_addr[i] & pmask[i]);
226 		}
227 
228 		if (i6a->s6_addr[i] != i6b->s6_addr[i])
229 			return false;
230 	}
231 
232 	return true;
233 }
234 
235 
236 /*!	Routing utility function: determines the least significant bit that is set
237 	in the given \a mask.
238 	\return the number of the first bit that is set (0-32, where 32 means
239 		that there's no bit set in the mask).
240 */
241 static int32
242 ipv6_first_mask_bit(const sockaddr *_mask)
243 {
244 	if (_mask == NULL)
245 		return 0;
246 
247 	const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
248 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
249 		if (pmask[i] == 0xff)
250 			continue;
251 
252 		for (uint8 bit = 0; bit < 8; bit++) {
253 			if ((pmask[i] & (1 << (7 - bit))) == 0)
254 				return i * 8 + bit;
255 		}
256 	}
257 
258 	return 128;
259 }
260 
261 
262 /*!	Routing utility function: checks the given \a mask for correctness (which
263 	means that (starting with LSB) consists zero or more unset bits, followed
264 	by bits that are all set).
265 	\return true if \a mask is ok, false if not
266 */
267 static bool
268 ipv6_check_mask(const sockaddr *_mask)
269 {
270 	if (_mask == NULL)
271 		return true;
272 
273 	bool zero = false;
274 	const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
275 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
276 		if (pmask[i] == 0xff) {
277 			if (zero)
278 				return false;
279 		} else if (pmask[i] == 0) {
280 			zero = true;
281 		} else {
282 			for (int8 bit = 7; bit >= 0; bit--) {
283 				if (pmask[i] & (1 << bit)) {
284 					if (zero)
285 						return false;
286 				} else {
287 					zero = true;
288 				}
289 			}
290 		}
291 	}
292 
293 	return true;
294 }
295 
296 
297 /*!	Creates a buffer for the given \a address and prints the address into
298 	it (hexadecimal representation in network byte order or '<none>').
299 	If \a printPort is set, the port is printed, too.
300 	\return B_OK if the address could be printed, \a buffer will point to
301 		the resulting string
302 	\return B_BAD_VALUE if no buffer has been given
303 	\return B_NO_MEMORY if the buffer could not be allocated,
304 		or does not have enogh space
305 */
306 static status_t
307 ipv6_print_address_buffer(const sockaddr *_address, char *buffer,
308 	size_t bufferSize, bool printPort)
309 {
310 	const sockaddr_in6 *address = (const sockaddr_in6 *)_address;
311 
312 	if (buffer == NULL)
313 		return B_BAD_VALUE;
314 
315 	if (address == NULL) {
316 		if (bufferSize < sizeof("<none>"))
317 			return B_NO_MEMORY;
318 		strcpy(buffer, "<none>");
319 	} else {
320 		if (printPort && bufferSize > 0) {
321 			*buffer = '[';
322 			buffer++;
323 			bufferSize--;
324 		}
325 
326 		if (!ip6_sprintf(&address->sin6_addr, buffer, bufferSize))
327 			return B_NO_MEMORY;
328 
329 		if (printPort) {
330 			char port[7];
331 			snprintf(port, sizeof(port), "]:%d", ntohs(address->sin6_port));
332 			if (bufferSize - strlen(buffer) < strlen(port) + 1)
333 				return B_NO_MEMORY;
334 			strcat(buffer, port);
335 		}
336 	}
337 
338 	return B_OK;
339 }
340 
341 
342 static status_t
343 ipv6_print_address(const sockaddr *_address, char **_buffer, bool printPort)
344 {
345 	if (_buffer == NULL)
346 		return B_BAD_VALUE;
347 
348 	char tmp[64];
349 	ipv6_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
350 
351 	*_buffer = strdup(tmp);
352 	if (*_buffer == NULL)
353 		return B_NO_MEMORY;
354 
355 	return B_OK;
356 }
357 
358 
359 /*!	Determines the port of the given \a address.
360 	\return uint16 representing the port-nr
361 */
362 static uint16
363 ipv6_get_port(const sockaddr *address)
364 {
365 	if (address == NULL || address->sa_len == 0)
366 		return 0;
367 
368 	return ((sockaddr_in6 *)address)->sin6_port;
369 }
370 
371 
372 /*!	Sets the port of the given \a address to \a port.
373 	\return B_OK if the port has been set
374 	\return B_BAD_VALUE if \a address is NULL or has not been initialized
375 */
376 static status_t
377 ipv6_set_port(sockaddr *address, uint16 port)
378 {
379 	if (address == NULL || address->sa_len == 0)
380 		return B_BAD_VALUE;
381 
382 	((sockaddr_in6 *)address)->sin6_port = port;
383 	return B_OK;
384 }
385 
386 
387 /*!	Sets \a address to \a from.
388 	\return B_OK if \a from has been copied into \a address
389 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
390 			address given in from has not been initialized
391 	\return B_MISMATCHED_VALUES if from is not of family AF_INET6
392 */
393 static status_t
394 ipv6_set_to(sockaddr *address, const sockaddr *from)
395 {
396 	if (address == NULL || from == NULL || from->sa_len == 0)
397 		return B_BAD_VALUE;
398 
399 	if (from->sa_family != AF_INET6)
400 		return B_MISMATCHED_VALUES;
401 
402 	memcpy(address, from, sizeof(sockaddr_in6));
403 	address->sa_len = sizeof(sockaddr_in6);
404 	return B_OK;
405 }
406 
407 
408 /*!	Updates missing parts in \a address with the values in \a from.
409 	\return B_OK if \a address has been updated from \a from
410 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
411 			address given in from has not been initialized
412 	\return B_MISMATCHED_VALUES if from is not of family AF_INET6
413 */
414 static status_t
415 ipv6_update_to(sockaddr *_address, const sockaddr *_from)
416 {
417 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
418 	const sockaddr_in6 *from = (const sockaddr_in6 *)_from;
419 
420 	if (address == NULL || from == NULL || from->sin6_len == 0)
421 		return B_BAD_VALUE;
422 
423 	if (from->sin6_family != AF_INET6)
424 		return B_BAD_VALUE;
425 
426 	address->sin6_family = AF_INET6;
427 	address->sin6_len = sizeof(sockaddr_in6);
428 
429 	if (address->sin6_port == 0)
430 		address->sin6_port = from->sin6_port;
431 
432 	if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) {
433 		memcpy(address->sin6_addr.s6_addr, from->sin6_addr.s6_addr,
434 			sizeof(in6_addr));
435 	}
436 
437 	return B_OK;
438 }
439 
440 
441 /*!	Sets \a address to the empty address (0.0.0.0).
442 	\return B_OK if \a address has been set
443 	\return B_BAD_VALUE if \a address is NULL
444 */
445 static status_t
446 ipv6_set_to_empty_address(sockaddr *address)
447 {
448 	if (address == NULL)
449 		return B_BAD_VALUE;
450 
451 	memset(address, 0, sizeof(sockaddr_in6));
452 	address->sa_len = sizeof(sockaddr_in6);
453 	address->sa_family = AF_INET6;
454 	return B_OK;
455 }
456 
457 
458 static status_t
459 ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
460 	const sockaddr *_address, const sockaddr *_mask)
461 {
462 	sockaddr_in6 *defaultMask = (sockaddr_in6 *)_defaultMask;
463 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
464 	sockaddr_in6 *mask = (sockaddr_in6 *)_mask;
465 
466 	if (address == NULL || defaultMask == NULL)
467 		return B_BAD_VALUE;
468 
469 	defaultMask->sin6_len = sizeof(sockaddr_in);
470 	defaultMask->sin6_family = AF_INET6;
471 	defaultMask->sin6_port = 0;
472 	if (mask != NULL) {
473 		memcpy(defaultMask->sin6_addr.s6_addr,
474 			mask->sin6_addr.s6_addr, sizeof(in6_addr));
475 	} else {
476 		// use /128 as the default mask
477 		memset(defaultMask->sin6_addr.s6_addr, 0xff, sizeof(in6_addr));
478 	}
479 
480 	return B_OK;
481 }
482 
483 
484 /*!	Computes a hash value of the given \a address.
485 	\return uint32 representing the hash value
486 */
487 static uint32
488 ipv6_hash_address(const struct sockaddr* _address, bool includePort)
489 {
490 	const sockaddr_in6* address = (const sockaddr_in6*)_address;
491 	if (address == NULL || address->sin6_len == 0)
492 		return 0;
493 
494 	// TODO: also use sin6_flowinfo and sin6_scope_id?
495 	uint32 port = includePort ? address->sin6_port : 0;
496 
497 	uint32 result = jenkins_hashword((const uint32*)&address->sin6_addr,
498 		sizeof(in6_addr) / sizeof(uint32), 0);
499 	return jenkins_hashword(&port, 1, result);
500 }
501 
502 
503 /*!	Computes a hash-value of the given addresses \a ourAddress
504 	and \a peerAddress.
505 	\return uint32 representing the hash-value
506 */
507 static uint32
508 ipv6_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
509 {
510 	uint32 result = ipv6_hash_address(peerAddress, true);
511 	return jenkins_hashword(&result, 1, ipv6_hash_address(ourAddress, true));
512 }
513 
514 
515 /*!	Adds the given \a address to the IP-checksum \a checksum.
516 	\return B_OK if \a address has been added to the checksum
517 	\return B_BAD_VALUE if either \a address or \a checksum is NULL or if
518 	        the given address is not initialized
519 */
520 static status_t
521 ipv6_checksum_address(Checksum *checksum, const sockaddr *address)
522 {
523 	if (checksum == NULL || address == NULL || address->sa_len == 0)
524 		return B_BAD_VALUE;
525 
526 	in6_addr &a = ((sockaddr_in6 *)address)->sin6_addr;
527 	for (uint32 i = 0; i < sizeof(in6_addr); i += 2)
528 		(*checksum) << *(uint16*)(a.s6_addr + i);
529 
530 	return B_OK;
531 }
532 
533 
534 static void
535 ipv6_get_loopback_address(sockaddr *_address)
536 {
537 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
538 	memset(address, 0, sizeof(sockaddr_in6));
539 	address->sin6_len = sizeof(sockaddr_in6);
540 	address->sin6_family = AF_INET6;
541 	memcpy(&address->sin6_addr, &in6addr_loopback, sizeof(in6_addr));
542 }
543 
544 
545 net_address_module_info gIPv6AddressModule = {
546 	{
547 		NULL,
548 		0,
549 		NULL
550 	},
551 	0, // flags
552 	ipv6_copy_address,
553 	ipv6_mask_address,
554 	ipv6_equal_addresses,
555 	ipv6_equal_ports,
556 	ipv6_equal_addresses_and_ports,
557 	ipv6_equal_masked_addresses,
558 	ipv6_is_empty_address,
559 	ipv6_is_same_family,
560 	ipv6_first_mask_bit,
561 	ipv6_check_mask,
562 	ipv6_print_address,
563 	ipv6_print_address_buffer,
564 	ipv6_get_port,
565 	ipv6_set_port,
566 	ipv6_set_to,
567 	ipv6_set_to_empty_address,
568 	ipv6_set_to_defaults,
569 	ipv6_update_to,
570 	ipv6_hash_address,
571 	ipv6_hash_address_pair,
572 	ipv6_checksum_address,
573 	ipv6_get_loopback_address
574 };
575