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
ipv6_mask_adress_inplace(sockaddr * address,const sockaddr * mask)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
ipv6_copy_address(const sockaddr * from,sockaddr ** to,bool replaceWithZeros=false,const sockaddr * mask=NULL)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
ipv6_mask_address(const sockaddr * address,const sockaddr * mask,sockaddr * result)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
ipv6_is_empty_address(const sockaddr * _address,bool checkPort)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
ipv6_is_same_family(const sockaddr * address)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
ipv6_equal_addresses(const sockaddr * a,const sockaddr * b)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
ipv6_equal_ports(const sockaddr * a,const sockaddr * b)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
ipv6_equal_addresses_and_ports(const sockaddr * a,const sockaddr * b)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
ipv6_equal_masked_addresses(const sockaddr * a,const sockaddr * b,const sockaddr * mask)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
ipv6_first_mask_bit(const sockaddr * _mask)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
ipv6_check_mask(const sockaddr * _mask)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
ipv6_print_address_buffer(const sockaddr * _address,char * buffer,size_t bufferSize,bool printPort)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
ipv6_print_address(const sockaddr * _address,char ** _buffer,bool printPort)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
ipv6_get_port(const sockaddr * address)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
ipv6_set_port(sockaddr * address,uint16 port)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
ipv6_set_to(sockaddr * address,const sockaddr * from)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
ipv6_update_to(sockaddr * _address,const sockaddr * _from)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
ipv6_set_to_empty_address(sockaddr * address)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
ipv6_set_to_defaults(sockaddr * _defaultMask,sockaddr * _defaultBroadcast,const sockaddr * _address,const sockaddr * _mask)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
ipv6_hash_address(const struct sockaddr * _address,bool includePort)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
ipv6_hash_address_pair(const sockaddr * ourAddress,const sockaddr * peerAddress)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
ipv6_checksum_address(Checksum * checksum,const sockaddr * address)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
ipv6_get_loopback_address(sockaddr * _address)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