xref: /haiku/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
1 /*
2  * Copyright 2006-2010, 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) return false;
122 	return IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr);
123 }
124 
125 
126 /*!	Checks if the given \a address is an Ipv6 address.
127 	\return false if \a address is NULL, or with family different from AF_INET
128 		true if it has AF_INET address family
129 */
130 static bool
131 ipv6_is_same_family(const sockaddr *address)
132 {
133 	if (address == NULL)
134 		return false;
135 
136 	return address->sa_family == AF_INET6;
137 }
138 
139 
140 /*!	Compares the IP-addresses of the two given address structures \a a and \a b.
141 	\return true if IP-addresses of \a a and \a b are equal, false if not
142 */
143 static bool
144 ipv6_equal_addresses(const sockaddr *a, const sockaddr *b)
145 {
146 	if (a == NULL && b == NULL)
147 		return true;
148 	if (a != NULL && b == NULL)
149 		return ipv6_is_empty_address(a, false);
150 	if (a == NULL && b != NULL)
151 		return ipv6_is_empty_address(b, false);
152 
153 	const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
154 	const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
155 	return !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
156 }
157 
158 
159 /*!	Compares the ports of the two given address structures \a a and \a b.
160 	\return true if ports of \a a and \a b are equal, false if not
161 */
162 static bool
163 ipv6_equal_ports(const sockaddr *a, const sockaddr *b)
164 {
165 	uint16 portA = a ? ((sockaddr_in6 *)a)->sin6_port : 0;
166 	uint16 portB = b ? ((sockaddr_in6 *)b)->sin6_port : 0;
167 	return portA == portB;
168 }
169 
170 
171 /*!	Compares the IP-addresses and ports of the two given address structures
172 	\a a and \a b.
173 	\return true if IP-addresses and ports of \a a and \a b are equal, false if
174 			not
175 */
176 static bool
177 ipv6_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
178 {
179 	if (a == NULL && b == NULL)
180 		return true;
181 	if (a != NULL && b == NULL)
182 		return ipv6_is_empty_address(a, true);
183 	if (a == NULL && b != NULL)
184 		return ipv6_is_empty_address(b, true);
185 
186 	const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
187 	const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
188 	return i6a->sin6_port == i6b->sin6_port
189 		&& !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
190 }
191 
192 
193 /*!	Applies the given \a mask two \a a and \a b and then checks whether
194 	the masked addresses match.
195 	\return true if \a a matches \a b after masking both, false if not
196 */
197 static bool
198 ipv6_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
199 	const sockaddr *mask)
200 {
201 	if (a == NULL && b == NULL)
202 		return true;
203 
204 	const in6_addr *i6a;
205 	if (a == NULL)
206 		i6a = &in6addr_any;
207 	else
208 		i6a = &((const sockaddr_in6*)a)->sin6_addr;
209 
210 	const in6_addr *i6b;
211 	if (b == NULL)
212 		i6b = &in6addr_any;
213 	else
214 		i6b = &((const sockaddr_in6*)b)->sin6_addr;
215 
216  	if (!mask)
217 		return !memcmp(i6a, i6b, sizeof(in6_addr));
218 
219 	const uint8 *pmask = ((const sockaddr_in6 *)mask)->sin6_addr.s6_addr;
220 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
221 		if (pmask[i] != 0xff) {
222 			return (i6a->s6_addr[i] & pmask[i])
223 				== (i6b->s6_addr[i] & pmask[i]);
224 		}
225 
226 		if (i6a->s6_addr[i] != i6b->s6_addr[i])
227 			return false;
228 	}
229 
230 	return true;
231 }
232 
233 
234 /*!	Routing utility function: determines the least significant bit that is set
235 	in the given \a mask.
236 	\return the number of the first bit that is set (0-32, where 32 means
237 		that there's no bit set in the mask).
238 */
239 static int32
240 ipv6_first_mask_bit(const sockaddr *_mask)
241 {
242 	if (_mask == NULL)
243 		return 0;
244 
245 	const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
246 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
247 		if (pmask[i] == 0xff)
248 			continue;
249 
250 		for (uint8 bit = 0; bit < 8; bit++) {
251 			if ((pmask[i] & (1 << (7 - bit))) == 0)
252 				return i * 8 + bit;
253 		}
254 	}
255 
256 	return 128;
257 }
258 
259 
260 /*!	Routing utility function: checks the given \a mask for correctness (which
261 	means that (starting with LSB) consists zero or more unset bits, followed
262 	by bits that are all set).
263 	\return true if \a mask is ok, false if not
264 */
265 static bool
266 ipv6_check_mask(const sockaddr *_mask)
267 {
268 	if (_mask == NULL)
269 		return true;
270 
271 	bool zero = false;
272 	const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
273 	for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
274 		if (pmask[i] == 0xff) {
275 			if (zero)
276 				return false;
277 		} else if (pmask[i] == 0) {
278 			zero = true;
279 		} else {
280 			for (int8 bit = 7; bit >= 0; bit--) {
281 				if (pmask[i] & (1 << bit)) {
282 					if (zero)
283 						return false;
284 				} else {
285 					zero = true;
286 				}
287 			}
288 		}
289 	}
290 
291 	return true;
292 }
293 
294 
295 /*!	Creates a buffer for the given \a address and prints the address into
296 	it (hexadecimal representation in network byte order or '<none>').
297 	If \a printPort is set, the port is printed, too.
298 	\return B_OK if the address could be printed, \a buffer will point to
299 		the resulting string
300 	\return B_BAD_VALUE if no buffer has been given
301 	\return B_NO_MEMORY if the buffer could not be allocated,
302 		or does not have enogh space
303 */
304 static status_t
305 ipv6_print_address_buffer(const sockaddr *_address, char *buffer,
306 	size_t bufferSize, bool printPort)
307 {
308 	const sockaddr_in6 *address = (const sockaddr_in6 *)_address;
309 
310 	if (buffer == NULL)
311 		return B_BAD_VALUE;
312 
313 	if (address == NULL) {
314 		if (bufferSize < sizeof("<none>"))
315 			return B_NO_MEMORY;
316 		strcpy(buffer, "<none>");
317 	} else {
318 		if (printPort && bufferSize > 0) {
319 			*buffer = '[';
320 			buffer++;
321 			bufferSize--;
322 		}
323 
324 		if (!ip6_sprintf(&address->sin6_addr, buffer, bufferSize))
325 			return B_NO_MEMORY;
326 
327 		if (printPort) {
328 			char port[7];
329 			sprintf(port, "]:%d", ntohs(address->sin6_port));
330 			if (bufferSize - strlen(buffer) < strlen(port) + 1)
331 				return B_NO_MEMORY;
332 			strcat(buffer, port);
333 		}
334 	}
335 
336 	return B_OK;
337 }
338 
339 
340 static status_t
341 ipv6_print_address(const sockaddr *_address, char **_buffer, bool printPort)
342 {
343 	if (_buffer == NULL)
344 		return B_BAD_VALUE;
345 
346 	char tmp[64];
347 	ipv6_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
348 
349 	*_buffer = strdup(tmp);
350 	if (*_buffer == NULL)
351 		return B_NO_MEMORY;
352 
353 	return B_OK;
354 }
355 
356 
357 /*!	Determines the port of the given \a address.
358 	\return uint16 representing the port-nr
359 */
360 static uint16
361 ipv6_get_port(const sockaddr *address)
362 {
363 	if (address == NULL || address->sa_len == 0)
364 		return 0;
365 
366 	return ((sockaddr_in6 *)address)->sin6_port;
367 }
368 
369 
370 /*!	Sets the port of the given \a address to \a port.
371 	\return B_OK if the port has been set
372 	\return B_BAD_VALUE if \a address is NULL or has not been initialized
373 */
374 static status_t
375 ipv6_set_port(sockaddr *address, uint16 port)
376 {
377 	if (address == NULL || address->sa_len == 0)
378 		return B_BAD_VALUE;
379 
380 	((sockaddr_in6 *)address)->sin6_port = port;
381 	return B_OK;
382 }
383 
384 
385 /*!	Sets \a address to \a from.
386 	\return B_OK if \a from has been copied into \a address
387 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
388 			address given in from has not been initialized
389 	\return B_MISMATCHED_VALUES if from is not of family AF_INET6
390 */
391 static status_t
392 ipv6_set_to(sockaddr *address, const sockaddr *from)
393 {
394 	if (address == NULL || from == NULL || from->sa_len == 0)
395 		return B_BAD_VALUE;
396 
397 	if (from->sa_family != AF_INET6)
398 		return B_MISMATCHED_VALUES;
399 
400 	memcpy(address, from, sizeof(sockaddr_in6));
401 	address->sa_len = sizeof(sockaddr_in6);
402 	return B_OK;
403 }
404 
405 
406 /*!	Updates missing parts in \a address with the values in \a from.
407 	\return B_OK if \a address has been updated from \a from
408 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
409 			address given in from has not been initialized
410 	\return B_MISMATCHED_VALUES if from is not of family AF_INET6
411 */
412 static status_t
413 ipv6_update_to(sockaddr *_address, const sockaddr *_from)
414 {
415 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
416 	const sockaddr_in6 *from = (const sockaddr_in6 *)_from;
417 
418 	if (address == NULL || from == NULL || from->sin6_len == 0)
419 		return B_BAD_VALUE;
420 
421 	if (from->sin6_family != AF_INET6)
422 		return B_BAD_VALUE;
423 
424 	address->sin6_family = AF_INET6;
425 	address->sin6_len = sizeof(sockaddr_in6);
426 
427 	if (address->sin6_port == 0)
428 		address->sin6_port = from->sin6_port;
429 
430 	if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) {
431 		memcpy(address->sin6_addr.s6_addr, from->sin6_addr.s6_addr,
432 			sizeof(in6_addr));
433 	}
434 
435 	return B_OK;
436 }
437 
438 
439 /*!	Sets \a address to the empty address (0.0.0.0).
440 	\return B_OK if \a address has been set
441 	\return B_BAD_VALUE if \a address is NULL
442 */
443 static status_t
444 ipv6_set_to_empty_address(sockaddr *address)
445 {
446 	if (address == NULL)
447 		return B_BAD_VALUE;
448 
449 	memset(address, 0, sizeof(sockaddr_in6));
450 	address->sa_len = sizeof(sockaddr_in6);
451 	address->sa_family = AF_INET6;
452 	return B_OK;
453 }
454 
455 
456 static status_t
457 ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
458 	const sockaddr *_address, const sockaddr *_mask)
459 {
460 	sockaddr_in6 *defaultMask = (sockaddr_in6 *)_defaultMask;
461 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
462 	sockaddr_in6 *mask = (sockaddr_in6 *)_mask;
463 
464 	if (address == NULL || defaultMask == NULL)
465 		return B_BAD_VALUE;
466 
467 	defaultMask->sin6_len = sizeof(sockaddr_in);
468 	defaultMask->sin6_family = AF_INET6;
469 	defaultMask->sin6_port = 0;
470 	if (mask != NULL) {
471 		memcpy(defaultMask->sin6_addr.s6_addr,
472 			mask->sin6_addr.s6_addr, sizeof(in6_addr));
473 	} else {
474 		// use /128 as the default mask
475 		memset(defaultMask->sin6_addr.s6_addr, 0xff, sizeof(in6_addr));
476 	}
477 
478 	return B_OK;
479 }
480 
481 
482 /*!	Computes a hash value of the given \a address.
483 	\return uint32 representing the hash value
484 */
485 static uint32
486 ipv6_hash_address(const struct sockaddr* _address, bool includePort)
487 {
488 	const sockaddr_in6* address = (const sockaddr_in6*)_address;
489 	if (address == NULL || address->sin6_len == 0)
490 		return 0;
491 
492 	// TODO: also use sin6_flowinfo and sin6_scope_id?
493 	uint32 port = includePort ? address->sin6_port : 0;
494 
495 	uint32 result = jenkins_hashword((const uint32*)&address->sin6_addr,
496 		sizeof(in6_addr) / sizeof(uint32), 0);
497 	return jenkins_hashword(&port, 1, result);
498 }
499 
500 
501 /*!	Computes a hash-value of the given addresses \a ourAddress
502 	and \a peerAddress.
503 	\return uint32 representing the hash-value
504 */
505 static uint32
506 ipv6_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
507 {
508 	uint32 result = ipv6_hash_address(peerAddress, true);
509 	return jenkins_hashword(&result, 1, ipv6_hash_address(ourAddress, true));
510 }
511 
512 
513 /*!	Adds the given \a address to the IP-checksum \a checksum.
514 	\return B_OK if \a address has been added to the checksum
515 	\return B_BAD_VALUE if either \a address or \a checksum is NULL or if
516 	        the given address is not initialized
517 */
518 static status_t
519 ipv6_checksum_address(struct Checksum *checksum, const sockaddr *address)
520 {
521 	if (checksum == NULL || address == NULL || address->sa_len == 0)
522 		return B_BAD_VALUE;
523 
524 	in6_addr &a = ((sockaddr_in6 *)address)->sin6_addr;
525 	for (uint32 i = 0; i < sizeof(in6_addr); i += 2)
526 		(*checksum) << *(uint16*)(a.s6_addr + i);
527 
528 	return B_OK;
529 }
530 
531 
532 static void
533 ipv6_get_loopback_address(sockaddr *_address)
534 {
535 	sockaddr_in6 *address = (sockaddr_in6 *)_address;
536 	memset(address, 0, sizeof(sockaddr_in6));
537 	address->sin6_len = sizeof(sockaddr_in6);
538 	address->sin6_family = AF_INET6;
539 	memcpy(&address->sin6_addr, &in6addr_loopback, sizeof(in6_addr));
540 }
541 
542 
543 net_address_module_info gIPv6AddressModule = {
544 	{
545 		NULL,
546 		0,
547 		NULL
548 	},
549 	0, // flags
550 	ipv6_copy_address,
551 	ipv6_mask_address,
552 	ipv6_equal_addresses,
553 	ipv6_equal_ports,
554 	ipv6_equal_addresses_and_ports,
555 	ipv6_equal_masked_addresses,
556 	ipv6_is_empty_address,
557 	ipv6_is_same_family,
558 	ipv6_first_mask_bit,
559 	ipv6_check_mask,
560 	ipv6_print_address,
561 	ipv6_print_address_buffer,
562 	ipv6_get_port,
563 	ipv6_set_port,
564 	ipv6_set_to,
565 	ipv6_set_to_empty_address,
566 	ipv6_set_to_defaults,
567 	ipv6_update_to,
568 	ipv6_hash_address,
569 	ipv6_hash_address_pair,
570 	ipv6_checksum_address,
571 	ipv6_get_loopback_address
572 };
573