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