xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
1 /*
2  * Copyright 2006-2009, 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 		return true;
105 
106 	return ((sockaddr_in *)address)->sin_addr.s_addr == 0
107 		&& (!checkPort || ((sockaddr_in *)address)->sin_port == 0);
108 }
109 
110 
111 /*!	Compares the IP-addresses of the two given address structures \a a and \a b.
112 	\return true if IP-addresses of \a a and \a b are equal, false if not
113 */
114 static bool
115 ipv4_equal_addresses(const sockaddr *a, const sockaddr *b)
116 {
117 	if (a == NULL && b == NULL)
118 		return true;
119 	if (a != NULL && b == NULL)
120 		return ipv4_is_empty_address(a, false);
121 	if (a == NULL && b != NULL)
122 		return ipv4_is_empty_address(b, false);
123 
124 	return ((sockaddr_in *)a)->sin_addr.s_addr
125 		== ((sockaddr_in *)b)->sin_addr.s_addr;
126 }
127 
128 
129 /*!	Compares the ports of the two given address structures \a a and \a b.
130 	\return true if ports of \a a and \a b are equal, false if not
131 */
132 static bool
133 ipv4_equal_ports(const sockaddr *a, const sockaddr *b)
134 {
135 	uint16 portA = a ? ((sockaddr_in *)a)->sin_port : 0;
136 	uint16 portB = b ? ((sockaddr_in *)b)->sin_port : 0;
137 	return portA == portB;
138 }
139 
140 
141 /*!	Compares the IP-addresses and ports of the two given address structures
142 	\a a and \a b.
143 	\return true if IP-addresses and ports of \a a and \a b are equal, false if
144 			not
145 */
146 static bool
147 ipv4_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
148 {
149 	if (a == NULL && b == NULL)
150 		return true;
151 	if (a != NULL && b == NULL)
152 		return ipv4_is_empty_address(a, true);
153 	if (a == NULL && b != NULL)
154 		return ipv4_is_empty_address(b, true);
155 
156 	return ((sockaddr_in *)a)->sin_addr.s_addr
157 			== ((sockaddr_in *)b)->sin_addr.s_addr
158 		&& ((sockaddr_in *)a)->sin_port == ((sockaddr_in *)b)->sin_port;
159 }
160 
161 
162 /*!	Applies the given \a mask two \a a and \a b and then checks whether
163 	the masked addresses match.
164 	\return true if \a a matches \a b after masking both, false if not
165 */
166 static bool
167 ipv4_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
168 	const sockaddr *mask)
169 {
170 	if (a == NULL && b == NULL)
171 		return true;
172 
173 	sockaddr emptyAddr;
174 	if (a == NULL || b == NULL) {
175 		memset(&emptyAddr, 0, sizeof(sockaddr_in));
176 		if (a == NULL)
177 			a = &emptyAddr;
178 		else if (b == NULL)
179 			b = &emptyAddr;
180 	}
181 
182 	uint32 aValue = ((sockaddr_in *)a)->sin_addr.s_addr;
183 	uint32 bValue = ((sockaddr_in *)b)->sin_addr.s_addr;
184 
185 	if (!mask)
186 		return aValue == bValue;
187 
188 	uint32 maskValue = ((sockaddr_in *)mask)->sin_addr.s_addr;
189 	return (aValue & maskValue) == (bValue & maskValue);
190 }
191 
192 
193 /*!	Routing utility function: determines the least significant bit that is set
194 	in the given \a mask.
195 	\return the number of the first bit that is set (0-32, where 32 means
196 		that there's no bit set in the mask).
197 */
198 static int32
199 ipv4_first_mask_bit(const sockaddr *_mask)
200 {
201 	if (_mask == NULL)
202 		return 0;
203 
204 	uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr);
205 
206 	// TODO: this can be optimized, there are also some nice assembler mnemonics
207 	// for this
208 	int8 bit = 0;
209 	for (uint32 bitMask = 1; bit < 32; bitMask <<= 1, bit++) {
210 		if (mask & bitMask)
211 			return bit;
212 	}
213 
214 	return 32;
215 }
216 
217 
218 /*!	Routing utility function: checks the given \a mask for correctness (which
219 	means that (starting with LSB) consists zero or more unset bits, followed
220 	by bits that are all set).
221 	\return true if \a mask is ok, false if not
222 */
223 static bool
224 ipv4_check_mask(const sockaddr *_mask)
225 {
226 	if (_mask == NULL)
227 		return true;
228 
229 	uint32 mask = ntohl(((const sockaddr_in *)_mask)->sin_addr.s_addr);
230 
231 	// A mask (from LSB) starts with zeros, after the first one, only ones
232 	// are allowed:
233 	bool zero = true;
234 	int8 bit = 0;
235 	for (uint32 bitMask = 1; bit < 32; bitMask <<= 1, bit++) {
236 		if (mask & bitMask) {
237 			if (zero)
238 				zero = false;
239 		} else if (!zero)
240 			return false;
241 	}
242 	return true;
243 }
244 
245 
246 /*!	Creates a buffer for the given \a address and prints the address into
247 	it (hexadecimal representation in host byte order or '<none>').
248 	If \a printPort is set, the port is printed, too.
249 	\return B_OK if the address could be printed, \a buffer will point to
250 		the resulting string
251 	\return B_BAD_VALUE if no buffer has been given
252 	\return B_NO_MEMORY if the buffer could not be allocated
253 */
254 static status_t
255 ipv4_print_address_buffer(const sockaddr *_address, char *buffer,
256 	size_t bufferSize, bool printPort)
257 {
258 	const sockaddr_in *address = (const sockaddr_in *)_address;
259 
260 	if (buffer == NULL)
261 		return B_BAD_VALUE;
262 
263 	if (address == NULL)
264 		strlcpy(buffer, "<none>", bufferSize);
265 	else {
266 		unsigned int addr = ntohl(address->sin_addr.s_addr);
267 
268 		if (printPort) {
269 			snprintf(buffer, bufferSize, "%u.%u.%u.%u:%u",
270 				(addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff,
271 				addr & 0xff, ntohs(address->sin_port));
272 		} else {
273 			snprintf(buffer, bufferSize, "%u.%u.%u.%u", (addr >> 24) & 0xff,
274 				(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
275 		}
276 	}
277 
278 	return B_OK;
279 }
280 
281 
282 static status_t
283 ipv4_print_address(const sockaddr *_address, char **_buffer, bool printPort)
284 {
285 	if (_buffer == NULL)
286 		return B_BAD_VALUE;
287 
288 	char tmp[64];
289 	ipv4_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
290 
291 	*_buffer = strdup(tmp);
292 	if (*_buffer == NULL)
293 		return B_NO_MEMORY;
294 
295 	return B_OK;
296 }
297 
298 
299 /*!	Determines the port of the given \a address.
300 	\return uint16 representing the port-nr
301 */
302 static uint16
303 ipv4_get_port(const sockaddr *address)
304 {
305 	if (address == NULL || address->sa_len == 0)
306 		return 0;
307 
308 	return ((sockaddr_in *)address)->sin_port;
309 }
310 
311 
312 /*!	Sets the port of the given \a address to \a port.
313 	\return B_OK if the port has been set
314 	\return B_BAD_VALUE if \a address is NULL or has not been initialized
315 */
316 static status_t
317 ipv4_set_port(sockaddr *address, uint16 port)
318 {
319 	if (address == NULL || address->sa_len == 0)
320 		return B_BAD_VALUE;
321 
322 	((sockaddr_in *)address)->sin_port = port;
323 	return B_OK;
324 }
325 
326 
327 /*!	Sets \a address to \a from.
328 	\return B_OK if \a from has been copied into \a address
329 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
330 			address given in from has not been initialized
331 	\return B_MISMATCHED_VALUES if from is not of family AF_INET
332 */
333 static status_t
334 ipv4_set_to(sockaddr *address, const sockaddr *from)
335 {
336 	if (address == NULL || from == NULL || from->sa_len == 0)
337 		return B_BAD_VALUE;
338 
339 	if (from->sa_family != AF_INET)
340 		return B_MISMATCHED_VALUES;
341 
342 	memcpy(address, from, sizeof(sockaddr_in));
343 	address->sa_len = sizeof(sockaddr_in);
344 	return B_OK;
345 }
346 
347 
348 /*!	Updates missing parts in \a address with the values in \a from.
349 	\return B_OK if \a address has been updated from \a from
350 	\return B_BAD_VALUE if either \a address or \a from is NULL or if the
351 			address given in from has not been initialized
352 	\return B_MISMATCHED_VALUES if from is not of family AF_INET
353 */
354 static status_t
355 ipv4_update_to(sockaddr *_address, const sockaddr *_from)
356 {
357 	sockaddr_in *address = (sockaddr_in *)_address;
358 	const sockaddr_in *from = (const sockaddr_in *)_from;
359 
360 	if (address == NULL || from == NULL || from->sin_len == 0)
361 		return B_BAD_VALUE;
362 
363 	if (from->sin_family != AF_INET)
364 		return B_BAD_VALUE;
365 
366 	address->sin_family = AF_INET;
367 	address->sin_len = sizeof(sockaddr_in);
368 
369 	if (address->sin_port == 0)
370 		address->sin_port = from->sin_port;
371 
372 	if (address->sin_addr.s_addr == INADDR_ANY)
373 		address->sin_addr.s_addr = from->sin_addr.s_addr;
374 
375 	return B_OK;
376 }
377 
378 
379 /*!	Sets \a address to the empty address (0.0.0.0).
380 	\return B_OK if \a address has been set
381 	\return B_BAD_VALUE if \a address is NULL
382 */
383 static status_t
384 ipv4_set_to_empty_address(sockaddr *address)
385 {
386 	if (address == NULL)
387 		return B_BAD_VALUE;
388 
389 	memset(address, 0, sizeof(sockaddr_in));
390 	address->sa_len = sizeof(sockaddr_in);
391 	address->sa_family = AF_INET;
392 	return B_OK;
393 }
394 
395 
396 static status_t
397 ipv4_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
398 	sockaddr *_address, sockaddr *_mask)
399 {
400 	sockaddr_in *defaultMask = (sockaddr_in *)_defaultMask;
401 	sockaddr_in *defaultBroadcast = (sockaddr_in *)_defaultBroadcast;
402 	sockaddr_in *address = (sockaddr_in *)_address;
403 	sockaddr_in *mask = (sockaddr_in *)_mask;
404 
405 	if (address == NULL || (defaultMask == NULL && defaultBroadcast == NULL))
406 		return B_BAD_VALUE;
407 
408 	in_addr_t net;
409 	if (mask == NULL) {
410 		// choose default netmask depending on the class of the address
411 		net = ntohl(address->sin_addr.s_addr);
412 		if (IN_CLASSA(net) || (net >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
413 			// class A, or loopback
414 			net = htonl(IN_CLASSA_NET);
415 		} else if (IN_CLASSB(net)) {
416 			// class B
417 			net = htonl(IN_CLASSB_NET);
418 		} else {
419 			// class C and rest
420 			net = htonl(IN_CLASSC_NET);
421 		}
422 	} else
423 		net = mask->sin_addr.s_addr;
424 
425 	if (defaultMask != NULL) {
426 		defaultMask->sin_len = sizeof(sockaddr_in);
427 		defaultMask->sin_family = AF_INET;
428 		defaultMask->sin_port = 0;
429 		defaultMask->sin_addr.s_addr = net;
430 	}
431 
432 	if (defaultBroadcast != NULL) {
433 		defaultBroadcast->sin_len = sizeof(sockaddr_in);
434 		defaultBroadcast->sin_family = AF_INET;
435 		defaultBroadcast->sin_port = 0;
436 		defaultBroadcast->sin_addr.s_addr = (address->sin_addr.s_addr & net)
437 			| ~net;
438 	}
439 
440 	return B_OK;
441 }
442 
443 
444 /*!	Computes a hash-value of the given addresses \a ourAddress
445 	and \a peerAddress.
446 	\return uint32 representing the hash-value
447 */
448 static uint32
449 ipv4_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
450 {
451 	const sockaddr_in *our = (const sockaddr_in *)ourAddress;
452 	const sockaddr_in *peer = (const sockaddr_in *)peerAddress;
453 
454 	bool haveOur = our && our->sin_len != 0;
455 	bool havePeer = peer && peer->sin_len != 0;
456 
457 	return
458 		((haveOur ? our->sin_port : 0)
459 			| ((havePeer ? peer->sin_port : 0) << 16))
460 		^ (haveOur ? our->sin_addr.s_addr : 0)
461 		^ (havePeer ? peer->sin_addr.s_addr : 0);
462 }
463 
464 
465 /*!	Adds the given \a address to the IP-checksum \a checksum.
466 	\return B_OK if \a address has been added to the checksum
467 	\return B_BAD_VALUE if either \a address or \a checksum is NULL or if
468 	        the given address is not initialized
469 */
470 static status_t
471 ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address)
472 {
473 	if (checksum == NULL || address == NULL || address->sa_len == 0)
474 		return B_BAD_VALUE;
475 
476 	(*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr;
477 	return B_OK;
478 }
479 
480 
481 net_address_module_info gIPv4AddressModule = {
482 	{
483 		NULL,
484 		0,
485 		NULL
486 	},
487 	ipv4_copy_address,
488 	ipv4_mask_address,
489 	ipv4_equal_addresses,
490 	ipv4_equal_ports,
491 	ipv4_equal_addresses_and_ports,
492 	ipv4_equal_masked_addresses,
493 	ipv4_is_empty_address,
494 	ipv4_first_mask_bit,
495 	ipv4_check_mask,
496 	ipv4_print_address,
497 	ipv4_print_address_buffer,
498 	ipv4_get_port,
499 	ipv4_set_port,
500 	ipv4_set_to,
501 	ipv4_set_to_empty_address,
502 	ipv4_set_to_defaults,
503 	ipv4_update_to,
504 	ipv4_hash_address_pair,
505 	ipv4_checksum_address,
506 	NULL // ipv4_matches_broadcast_address,
507 };
508