xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/ipv4_address.cpp (revision f23596149e0d173463f70629581aa10cc305d32e)
1 /*
2  * Copyright 2006, 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(const sockaddr *address, char **_buffer, bool printPort)
255 {
256 	if (_buffer == NULL)
257 		return B_BAD_VALUE;
258 
259 	int bufLen = printPort ? 15 : 9;
260 	char *buffer  = (char *)malloc(bufLen);
261 	if (buffer == NULL)
262 		return B_NO_MEMORY;
263 
264 	if (address == NULL)
265 		strcpy(buffer, "<none>");
266 	else if (printPort) {
267 		sprintf(buffer, "%08lx:%u", ntohl(((sockaddr_in *)address)->sin_addr.s_addr),
268 			ntohs(((sockaddr_in *)address)->sin_port));
269 	} else
270 		sprintf(buffer, "%08lx", ntohl(((sockaddr_in *)address)->sin_addr.s_addr));
271 	*_buffer = buffer;
272 	return B_OK;
273 }
274 
275 
276 /*!
277 	Determines the port of the given \a address.
278 	\return uint16 representing the port-nr
279 */
280 static uint16
281 ipv4_get_port(const sockaddr *address)
282 {
283 	if (address == NULL)
284 		return 0;
285 
286 	return ((sockaddr_in *)address)->sin_port;
287 }
288 
289 
290 /*!
291 	Sets the port of the given \a address to \a port.
292 	\return B_OK if the port has been set
293 	\return B_BAD_VALUE if \a address is NULL
294 */
295 static status_t
296 ipv4_set_port(sockaddr *address, uint16 port)
297 {
298 	if (address == NULL)
299 		return B_BAD_VALUE;
300 
301 	((sockaddr_in *)address)->sin_port = port;
302 	return B_OK;
303 }
304 
305 
306 /*!
307 	Sets \a address to \a from.
308 	\return B_OK if \a from has been copied into \a address
309 	\return B_BAD_VALUE if either \a address or \a from is NULL
310 	\return B_MISMATCHED_VALUES if from is not of family AF_INET
311 */
312 static status_t
313 ipv4_set_to(sockaddr *address, const sockaddr *from)
314 {
315 	if (address == NULL || from == NULL)
316 		return B_BAD_VALUE;
317 
318 	if (from->sa_family != AF_INET)
319 		return B_MISMATCHED_VALUES;
320 
321 	memcpy(address, from, sizeof(sockaddr_in));
322 	address->sa_len = sizeof(sockaddr_in);
323 	return B_OK;
324 }
325 
326 
327 /*!
328 	Sets \a address to the empty address (0.0.0.0).
329 	\return B_OK if \a address has been set
330 	\return B_BAD_VALUE if \a address is NULL
331 */
332 static status_t
333 ipv4_set_to_empty_address(sockaddr *address)
334 {
335 	if (address == NULL)
336 		return B_BAD_VALUE;
337 
338 	memset(address, 0, sizeof(sockaddr_in));
339 	address->sa_len = sizeof(sockaddr_in);
340 	address->sa_family = AF_INET;
341 	return B_OK;
342 }
343 
344 
345 /*!
346 	Computes a hash-value of the given addresses \a ourAddress
347 	and \a peerAddress.
348 	\return uint32 representing the hash-value
349 */
350 static uint32
351 ipv4_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
352 {
353 	int32 hash = (((sockaddr_in *)ourAddress)->sin_port
354 						| ((sockaddr_in *)peerAddress)->sin_port << 16)
355 					^ ((sockaddr_in *)ourAddress)->sin_addr.s_addr
356 					^ ((sockaddr_in *)peerAddress)->sin_addr.s_addr;
357 	return hash;
358 }
359 
360 
361 /*!
362 	Adds the given \a address to the IP-checksum \a checksum.
363 	\return B_OK if \a address has been added to the checksum
364 	\return B_BAD_VALUE if either \a address or \a checksum is NULL
365 */
366 static status_t
367 ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address)
368 {
369 	if (checksum == NULL || address == NULL)
370 		return B_BAD_VALUE;
371 
372 	(*checksum) << (uint32)((sockaddr_in *)address)->sin_addr.s_addr;
373 	return B_OK;
374 }
375 
376 
377 net_address_module_info gIPv4AddressModule = {
378 	{
379 		NULL,
380 		0,
381 		NULL
382 	},
383 	ipv4_copy_address,
384 	ipv4_mask_address,
385 	ipv4_equal_addresses,
386 	ipv4_equal_ports,
387 	ipv4_equal_addresses_and_ports,
388 	ipv4_equal_masked_addresses,
389 	ipv4_is_empty_address,
390 	ipv4_first_mask_bit,
391 	ipv4_check_mask,
392 	ipv4_print_address,
393 	ipv4_get_port,
394 	ipv4_set_port,
395 	ipv4_set_to,
396 	ipv4_set_to_empty_address,
397 	ipv4_hash_address_pair,
398 	ipv4_checksum_address,
399 	NULL // ipv4_matches_broadcast_address,
400 };
401