xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp (revision 1a76488fc88584bf66b9751d7fb9b6527ac20d87)
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  */
9 
10 
11 #include <net_datalink.h>
12 
13 #include <ByteOrder.h>
14 #include <KernelExport.h>
15 
16 #include <NetUtilities.h>
17 
18 #include <memory.h>
19 #include <netinet/in.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 
24 /*!	Routing utility function: copies address \a from into a new address
25 	that is put into \a to.
26 	If \a replaceWithZeros is set \a from will be replaced by an empty
27 	address.
28 	If a \a mask is given it is applied to \a from (such that \a to is the
29 	result of \a from & \a mask).
30 	\return B_OK if the address could be copied
31 	\return B_NO_MEMORY if the new address could not be allocated
32 	\return B_BAD_VALUE if any of \a from or \a mask refers to an uninitialized
33 			address
34 	\return B_MISMATCHED_VALUES if \a address does not match family AF_INET
35 */
36 static status_t
37 ipv4_copy_address(const sockaddr *from, sockaddr **to,
38 	bool replaceWithZeros = false, const sockaddr *mask = NULL)
39 {
40 	if (replaceWithZeros) {
41 		*to = (sockaddr *)malloc(sizeof(sockaddr_in));
42 		if (*to == NULL)
43 			return B_NO_MEMORY;
44 
45 		memset(*to, 0, sizeof(sockaddr_in));
46 		(*to)->sa_family = AF_INET;
47 		(*to)->sa_len = sizeof(sockaddr_in);
48 	} else {
49 		if (from == NULL)
50 			return B_OK;
51 		if (from->sa_len == 0 || (mask != NULL && mask->sa_len == 0))
52 			return B_BAD_VALUE;
53 		if (from->sa_family != AF_INET)
54 			return B_MISMATCHED_VALUES;
55 
56 		*to = (sockaddr *)malloc(sizeof(sockaddr_in));
57 		if (*to == NULL)
58 			return B_NO_MEMORY;
59 
60 		memcpy(*to, from, sizeof(sockaddr_in));
61 
62 		if (mask != NULL) {
63 			((sockaddr_in *)*to)->sin_addr.s_addr
64 				&= ((const sockaddr_in *)mask)->sin_addr.s_addr;
65 		}
66 	}
67 	return B_OK;
68 }
69 
70 
71 /*!	Routing utility function: applies \a mask to given \a address and puts
72 	the resulting address into \a result.
73 	\return B_OK if the mask has been applied
74 	\return B_BAD_VALUE if \a address is NULL or if any of \a address or \a mask
75 			refers to an uninitialized address
76 */
77 static status_t
78 ipv4_mask_address(const sockaddr *address, const sockaddr *mask,
79 	sockaddr *result)
80 {
81 	if (address == NULL || address->sa_len == 0 || result == NULL
82 			|| (mask != NULL && mask->sa_len == 0))
83 		return B_BAD_VALUE;
84 
85 	memcpy(result, address, sizeof(sockaddr_in));
86 	if (mask != NULL) {
87 		((sockaddr_in *)result)->sin_addr.s_addr
88 			&= ((sockaddr_in *)mask)->sin_addr.s_addr;
89 	}
90 
91 	return B_OK;
92 }
93 
94 
95 /*!	Checks if the given \a address is the empty address. By default, the port
96 	is checked, too, but you can avoid that by passing \a checkPort = false.
97 	\return true if \a address is NULL, uninitialized or the empty address,
98 		false if not
99 */
100 static bool
101 ipv4_is_empty_address(const sockaddr *address, bool checkPort)
102 {
103 	if (address == NULL || address->sa_len == 0
104 		|| address->sa_family == AF_UNSPEC)
105 		return true;
106 
107 	return ((sockaddr_in *)address)->sin_addr.s_addr == 0
108 		&& (!checkPort || ((sockaddr_in *)address)->sin_port == 0);
109 }
110 
111 
112 /*!	Checks if the given \a address is an IPv4 address.
113 	\return false if \a address is NULL, or with family different from AF_INET
114 		true if it has AF_INET address family
115 */
116 static bool
117 ipv4_is_same_family(const sockaddr *address)
118 {
119 	if (address == NULL)
120 		return false;
121 
122 	return address->sa_family == AF_INET;
123 }
124 
125 
126 /*!	Compares the IP-addresses of the two given address structures \a a and \a b.
127 	\return true if IP-addresses of \a a and \a b are equal, false if not
128 */
129 static bool
130 ipv4_equal_addresses(const sockaddr *a, const sockaddr *b)
131 {
132 	if (a == NULL && b == NULL)
133 		return true;
134 	if (a != NULL && b == NULL)
135 		return ipv4_is_empty_address(a, false);
136 	if (a == NULL && b != NULL)
137 		return ipv4_is_empty_address(b, false);
138 
139 	return ((sockaddr_in *)a)->sin_addr.s_addr
140 		== ((sockaddr_in *)b)->sin_addr.s_addr;
141 }
142 
143 
144 /*!	Compares the ports of the two given address structures \a a and \a b.
145 	\return true if ports of \a a and \a b are equal, false if not
146 */
147 static bool
148 ipv4_equal_ports(const sockaddr *a, const sockaddr *b)
149 {
150 	uint16 portA = a ? ((sockaddr_in *)a)->sin_port : 0;
151 	uint16 portB = b ? ((sockaddr_in *)b)->sin_port : 0;
152 	return portA == portB;
153 }
154 
155 
156 /*!	Compares the IP-addresses and ports of the two given address structures
157 	\a a and \a b.
158 	\return true if IP-addresses and ports of \a a and \a b are equal, false if
159 			not
160 */
161 static bool
162 ipv4_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
163 {
164 	if (a == NULL && b == NULL)
165 		return true;
166 	if (a != NULL && b == NULL)
167 		return ipv4_is_empty_address(a, true);
168 	if (a == NULL && b != NULL)
169 		return ipv4_is_empty_address(b, true);
170 
171 	return ((sockaddr_in *)a)->sin_addr.s_addr
172 			== ((sockaddr_in *)b)->sin_addr.s_addr
173 		&& ((sockaddr_in *)a)->sin_port == ((sockaddr_in *)b)->sin_port;
174 }
175 
176 
177 /*!	Applies the given \a mask two \a a and \a b and then checks whether
178 	the masked addresses match.
179 	\return true if \a a matches \a b after masking both, false if not
180 */
181 static bool
182 ipv4_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
183 	const sockaddr *mask)
184 {
185 	if (a == NULL && b == NULL)
186 		return true;
187 
188 	sockaddr emptyAddr;
189 	if (a == NULL || b == NULL) {
190 		memset(&emptyAddr, 0, sizeof(sockaddr_in));
191 		if (a == NULL)
192 			a = &emptyAddr;
193 		else if (b == NULL)
194 			b = &emptyAddr;
195 	}
196 
197 	uint32 aValue = ((sockaddr_in *)a)->sin_addr.s_addr;
198 	uint32 bValue = ((sockaddr_in *)b)->sin_addr.s_addr;
199 
200 	if (!mask)
201 		return aValue == bValue;
202 
203 	uint32 maskValue = ((sockaddr_in *)mask)->sin_addr.s_addr;
204 	return (aValue & maskValue) == (bValue & maskValue);
205 }
206 
207 
208 /*!	Routing utility function: determines the least significant bit that is set
209 	in the given \a mask.
210 	\return the number of the first bit that is set (0-32, where 32 means
211 		that there's no bit set in the mask).
212 */
213 static int32
214 ipv4_first_mask_bit(const sockaddr *_mask)
215 {
216 	if (_mask == NULL)
217 		return 0;
218 
219 	uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr);
220 
221 	// TODO: this can be optimized, there are also some nice assembler mnemonics
222 	// for this
223 	int8 bit = 0;
224 	for (uint32 bitMask = 1; bit < 32; bitMask <<= 1, bit++) {
225 		if (mask & bitMask)
226 			return bit;
227 	}
228 
229 	return 32;
230 }
231 
232 
233 /*!	Routing utility function: checks the given \a mask for correctness (which
234 	means that (starting with LSB) consists zero or more unset bits, followed
235 	by bits that are all set).
236 	\return true if \a mask is ok, false if not
237 */
238 static bool
239 ipv4_check_mask(const sockaddr *_mask)
240 {
241 	if (_mask == NULL)
242 		return true;
243 
244 	uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr);
245 
246 	// A mask (from LSB) starts with zeros, after the first one, only ones
247 	// are allowed:
248 	bool zero = true;
249 	int8 bit = 0;
250 	for (uint32 bitMask = 1; bit < 32; bitMask <<= 1, bit++) {
251 		if (mask & bitMask) {
252 			if (zero)
253 				zero = false;
254 		} else if (!zero)
255 			return false;
256 	}
257 	return true;
258 }
259 
260 
261 /*!	Creates a buffer for the given \a address and prints the address into
262 	it (hexadecimal representation in host byte order or '<none>').
263 	If \a printPort is set, the port is printed, too.
264 	\return B_OK if the address could be printed, \a buffer will point to
265 		the resulting string
266 	\return B_BAD_VALUE if no buffer has been given
267 	\return B_NO_MEMORY if the buffer could not be allocated
268 */
269 static status_t
270 ipv4_print_address_buffer(const sockaddr *_address, char *buffer,
271 	size_t bufferSize, bool printPort)
272 {
273 	const sockaddr_in *address = (const sockaddr_in *)_address;
274 
275 	if (buffer == NULL)
276 		return B_BAD_VALUE;
277 
278 	if (address == NULL)
279 		strlcpy(buffer, "<none>", bufferSize);
280 	else {
281 		unsigned int addr = ntohl(address->sin_addr.s_addr);
282 
283 		if (printPort) {
284 			snprintf(buffer, bufferSize, "%u.%u.%u.%u:%u",
285 				(addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff,
286 				addr & 0xff, ntohs(address->sin_port));
287 		} else {
288 			snprintf(buffer, bufferSize, "%u.%u.%u.%u", (addr >> 24) & 0xff,
289 				(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
290 		}
291 	}
292 
293 	return B_OK;
294 }
295 
296 
297 static status_t
298 ipv4_print_address(const sockaddr *_address, char **_buffer, bool printPort)
299 {
300 	if (_buffer == NULL)
301 		return B_BAD_VALUE;
302 
303 	char tmp[64];
304 	ipv4_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
305 
306 	*_buffer = strdup(tmp);
307 	if (*_buffer == NULL)
308 		return B_NO_MEMORY;
309 
310 	return B_OK;
311 }
312 
313 
314 /*!	Determines the port of the given \a address.
315 	\return uint16 representing the port-nr
316 */
317 static uint16
318 ipv4_get_port(const sockaddr *address)
319 {
320 	if (address == NULL || address->sa_len == 0)
321 		return 0;
322 
323 	return ((sockaddr_in *)address)->sin_port;
324 }
325 
326 
327 /*!	Sets the port of the given \a address to \a port.
328 	\return B_OK if the port has been set
329 	\return B_BAD_VALUE if \a address is NULL or has not been initialized
330 */
331 static status_t
332 ipv4_set_port(sockaddr *address, uint16 port)
333 {
334 	if (address == NULL || address->sa_len == 0)
335 		return B_BAD_VALUE;
336 
337 	((sockaddr_in *)address)->sin_port = port;
338 	return B_OK;
339 }
340 
341 
342 /*!	Sets \a address to \a from.
343 	\return B_OK if \a from has been copied into \a address
344 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
345 			address given in from has not been initialized
346 	\return B_MISMATCHED_VALUES if from is not of family AF_INET
347 */
348 static status_t
349 ipv4_set_to(sockaddr *address, const sockaddr *from)
350 {
351 	if (address == NULL || from == NULL || from->sa_len == 0)
352 		return B_BAD_VALUE;
353 
354 	if (from->sa_family != AF_INET)
355 		return B_MISMATCHED_VALUES;
356 
357 	memcpy(address, from, sizeof(sockaddr_in));
358 	address->sa_len = sizeof(sockaddr_in);
359 	return B_OK;
360 }
361 
362 
363 /*!	Updates missing parts in \a address with the values in \a from.
364 	\return B_OK if \a address has been updated from \a from
365 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
366 			address given in from has not been initialized
367 	\return B_MISMATCHED_VALUES if from is not of family AF_INET
368 */
369 static status_t
370 ipv4_update_to(sockaddr *_address, const sockaddr *_from)
371 {
372 	sockaddr_in *address = (sockaddr_in *)_address;
373 	const sockaddr_in *from = (const sockaddr_in *)_from;
374 
375 	if (address == NULL || from == NULL || from->sin_len == 0)
376 		return B_BAD_VALUE;
377 
378 	if (from->sin_family != AF_INET)
379 		return B_BAD_VALUE;
380 
381 	address->sin_family = AF_INET;
382 	address->sin_len = sizeof(sockaddr_in);
383 
384 	if (address->sin_port == 0)
385 		address->sin_port = from->sin_port;
386 
387 	if (address->sin_addr.s_addr == INADDR_ANY)
388 		address->sin_addr.s_addr = from->sin_addr.s_addr;
389 
390 	return B_OK;
391 }
392 
393 
394 /*!	Sets \a address to the empty address (0.0.0.0).
395 	\return B_OK if \a address has been set
396 	\return B_BAD_VALUE if \a address is NULL
397 */
398 static status_t
399 ipv4_set_to_empty_address(sockaddr *address)
400 {
401 	if (address == NULL)
402 		return B_BAD_VALUE;
403 
404 	memset(address, 0, sizeof(sockaddr_in));
405 	address->sa_len = sizeof(sockaddr_in);
406 	address->sa_family = AF_INET;
407 	return B_OK;
408 }
409 
410 
411 static status_t
412 ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
413 	const sockaddr *_address, const sockaddr *_mask)
414 {
415 	sockaddr_in *defaultMask = (sockaddr_in *)_defaultMask;
416 	sockaddr_in *defaultBroadcast = (sockaddr_in *)_defaultBroadcast;
417 	const sockaddr_in *address = (const sockaddr_in *)_address;
418 	const sockaddr_in *mask = (const sockaddr_in *)_mask;
419 
420 	if (address == NULL || (defaultMask == NULL && defaultBroadcast == NULL))
421 		return B_BAD_VALUE;
422 
423 	in_addr_t net;
424 	if (mask == NULL) {
425 		// choose default netmask depending on the class of the address
426 		net = ntohl(address->sin_addr.s_addr);
427 		if (IN_CLASSA(net) || (net >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
428 			// class A, or loopback
429 			net = htonl(IN_CLASSA_NET);
430 		} else if (IN_CLASSB(net)) {
431 			// class B
432 			net = htonl(IN_CLASSB_NET);
433 		} else {
434 			// class C and rest
435 			net = htonl(IN_CLASSC_NET);
436 		}
437 	} else
438 		net = mask->sin_addr.s_addr;
439 
440 	if (defaultMask != NULL) {
441 		defaultMask->sin_len = sizeof(sockaddr_in);
442 		defaultMask->sin_family = AF_INET;
443 		defaultMask->sin_port = 0;
444 		defaultMask->sin_addr.s_addr = net;
445 	}
446 
447 	if (defaultBroadcast != NULL) {
448 		defaultBroadcast->sin_len = sizeof(sockaddr_in);
449 		defaultBroadcast->sin_family = AF_INET;
450 		defaultBroadcast->sin_port = 0;
451 		defaultBroadcast->sin_addr.s_addr = address->sin_addr.s_addr | ~net;
452 	}
453 
454 	return B_OK;
455 }
456 
457 
458 /*!	Computes a hash value of the given \a address.
459 	\return uint32 representing the hash value
460 */
461 static uint32
462 ipv4_hash_address(const struct sockaddr* _address, bool includePort)
463 {
464 	const sockaddr_in* address = (const sockaddr_in*)_address;
465 	if (address == NULL || address->sin_len == 0)
466 		return 0;
467 
468 	if (includePort)
469 		return address->sin_port ^ address->sin_addr.s_addr;
470 
471 	return address->sin_addr.s_addr;
472 }
473 
474 
475 /*!	Computes a hash-value of the given addresses \a ourAddress
476 	and \a peerAddress.
477 	\return uint32 representing the hash-value
478 */
479 static uint32
480 ipv4_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
481 {
482 	const sockaddr_in *our = (const sockaddr_in *)ourAddress;
483 	const sockaddr_in *peer = (const sockaddr_in *)peerAddress;
484 
485 	bool haveOur = our && our->sin_len != 0;
486 	bool havePeer = peer && peer->sin_len != 0;
487 
488 	return
489 		((haveOur ? our->sin_port : 0)
490 			| ((havePeer ? peer->sin_port : 0) << 16))
491 		^ (haveOur ? our->sin_addr.s_addr : 0)
492 		^ (havePeer ? peer->sin_addr.s_addr : 0);
493 }
494 
495 
496 /*!	Adds the given \a address to the IP-checksum \a checksum.
497 	\return B_OK if \a address has been added to the checksum
498 	\return B_BAD_VALUE if either \a address or \a checksum is NULL or if
499 	        the given address is not initialized
500 */
501 static status_t
502 ipv4_checksum_address(Checksum *checksum, const sockaddr *address)
503 {
504 	if (checksum == NULL || address == NULL || address->sa_len == 0)
505 		return B_BAD_VALUE;
506 
507 	(*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr;
508 	return B_OK;
509 }
510 
511 
512 static void
513 ipv4_get_loopback_address(sockaddr *_address)
514 {
515 	sockaddr_in *address = (sockaddr_in *)_address;
516 	memset(address, 0, sizeof(sockaddr_in));
517 	address->sin_len = sizeof(sockaddr_in);
518 	address->sin_family = AF_INET;
519 	address->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
520 }
521 
522 
523 net_address_module_info gIPv4AddressModule = {
524 	{
525 		NULL,
526 		0,
527 		NULL
528 	},
529 	NET_ADDRESS_MODULE_FLAG_BROADCAST_ADDRESS,
530 	ipv4_copy_address,
531 	ipv4_mask_address,
532 	ipv4_equal_addresses,
533 	ipv4_equal_ports,
534 	ipv4_equal_addresses_and_ports,
535 	ipv4_equal_masked_addresses,
536 	ipv4_is_empty_address,
537 	ipv4_is_same_family,
538 	ipv4_first_mask_bit,
539 	ipv4_check_mask,
540 	ipv4_print_address,
541 	ipv4_print_address_buffer,
542 	ipv4_get_port,
543 	ipv4_set_port,
544 	ipv4_set_to,
545 	ipv4_set_to_empty_address,
546 	ipv4_set_to_defaults,
547 	ipv4_update_to,
548 	ipv4_hash_address,
549 	ipv4_hash_address_pair,
550 	ipv4_checksum_address,
551 	ipv4_get_loopback_address
552 };
553