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
26const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
27const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
28
29
30static void
31ipv6_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*/
53static status_t
54ipv6_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*/
92static status_t
93ipv6_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*/
113static bool
114ipv6_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*/
132static bool
133ipv6_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*/
145static bool
146ipv6_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*/
164static bool
165ipv6_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*/
178static bool
179ipv6_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*/
199static bool
200ipv6_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*/
241static int32
242ipv6_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*/
267static bool
268ipv6_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*/
306static status_t
307ipv6_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			sprintf(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
342static status_t
343ipv6_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*/
362static uint16
363ipv6_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*/
376static status_t
377ipv6_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*/
393static status_t
394ipv6_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*/
414static status_t
415ipv6_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*/
445static status_t
446ipv6_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
458static status_t
459ipv6_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*/
487static uint32
488ipv6_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*/
507static uint32
508ipv6_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*/
520static status_t
521ipv6_checksum_address(struct 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
534static void
535ipv6_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
545net_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