xref: /haiku/src/add-ons/kernel/network/protocols/icmp/icmp.cpp (revision b28ed9e04a771e5de38be68abd08148c0bbafc56)
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  */
8 
9 
10 /*!	RFC 792 details the ICMP protocol, RFC 1122 lists when an ICMP error must,
11 	shall, or must not be sent.
12 */
13 
14 
15 #include "icmp.h"
16 
17 #include <algorithm>
18 #include <netinet/in.h>
19 #include <new>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <KernelExport.h>
24 #include <OS.h>
25 
26 #include <net_datalink.h>
27 #include <net_protocol.h>
28 #include <net_stack.h>
29 #include <NetBufferUtilities.h>
30 #include <NetUtilities.h>
31 
32 #include "ipv4.h"
33 
34 
35 //#define TRACE_ICMP
36 #ifdef TRACE_ICMP
37 #	define TRACE(x...) dprintf(x)
38 #else
39 #	define TRACE(x...) ;
40 #endif
41 
42 
43 struct icmp_header {
44 	uint8	type;
45 	uint8	code;
46 	uint16	checksum;
47 	union {
48 		struct {
49 			uint16	id;
50 			uint16	sequence;
51 		} echo;
52 		struct {
53 			in_addr_t gateway;
54 		} redirect;
55 		struct {
56 			uint16	_reserved;
57 			uint16	next_mtu;
58 		} path_mtu;
59 		struct {
60 			uint8	pointer;
61 			uint8	_reserved[3];
62 		} parameter_problem;
63 
64 		uint32 zero;
65 	};
66 };
67 
68 typedef NetBufferField<uint16, offsetof(icmp_header, checksum)>
69 	ICMPChecksumField;
70 
71 
72 struct icmp_protocol : net_protocol {
73 };
74 
75 
76 net_buffer_module_info* gBufferModule;
77 static net_stack_module_info* sStackModule;
78 
79 
80 #ifdef TRACE_ICMP
81 
82 
83 static const char*
84 net_error_to_string(net_error error)
85 {
86 #define CODE(x) case x: return #x;
87 	switch (error) {
88 		CODE(B_NET_ERROR_REDIRECT_HOST)
89 		CODE(B_NET_ERROR_UNREACH_NET)
90 		CODE(B_NET_ERROR_UNREACH_HOST)
91 		CODE(B_NET_ERROR_UNREACH_PROTOCOL)
92 		CODE(B_NET_ERROR_UNREACH_PORT)
93 		CODE(B_NET_ERROR_MESSAGE_SIZE)
94 		CODE(B_NET_ERROR_TRANSIT_TIME_EXCEEDED)
95 		CODE(B_NET_ERROR_REASSEMBLY_TIME_EXCEEDED)
96 		CODE(B_NET_ERROR_PARAMETER_PROBLEM)
97 		CODE(B_NET_ERROR_QUENCH)
98 		default:
99 			return "unknown";
100 	}
101 #undef CODE
102 }
103 
104 
105 #endif	// TRACE_ICMP
106 
107 
108 static net_domain*
109 get_domain(struct net_buffer* buffer)
110 {
111 	net_domain* domain;
112 	if (buffer->interface_address != NULL)
113 		domain = buffer->interface_address->domain;
114 	else
115 		domain = sStackModule->get_domain(buffer->source->sa_family);
116 
117 	if (domain == NULL || domain->module == NULL)
118 		return NULL;
119 
120 	return domain;
121 }
122 
123 
124 static void
125 fill_sockaddr_in(sockaddr_in* target, in_addr_t address)
126 {
127 	target->sin_family = AF_INET;
128 	target->sin_len = sizeof(sockaddr_in);
129 	target->sin_port = 0;
130 	target->sin_addr.s_addr = address;
131 }
132 
133 
134 static bool
135 is_icmp_error(uint8 type)
136 {
137 	return type == ICMP_TYPE_UNREACH
138 		|| type == ICMP_TYPE_PARAMETER_PROBLEM
139 		|| type == ICMP_TYPE_REDIRECT
140 		|| type == ICMP_TYPE_TIME_EXCEEDED
141 		|| type == ICMP_TYPE_SOURCE_QUENCH;
142 }
143 
144 
145 static net_error
146 icmp_to_net_error(uint8 type, uint8 code)
147 {
148 	switch (type) {
149 		case ICMP_TYPE_UNREACH:
150 			switch (code) {
151 				case ICMP_CODE_FRAGMENTATION_NEEDED:
152 					return B_NET_ERROR_MESSAGE_SIZE;
153 				case ICMP_CODE_NET_UNREACH:
154 					return B_NET_ERROR_UNREACH_NET;
155 				case ICMP_CODE_HOST_UNREACH:
156 					return B_NET_ERROR_UNREACH_HOST;
157 				case ICMP_CODE_PROTOCOL_UNREACH:
158 					return B_NET_ERROR_UNREACH_PROTOCOL;
159 				case ICMP_CODE_PORT_UNREACH:
160 					return B_NET_ERROR_UNREACH_PORT;
161 			}
162 			break;
163 
164 		case ICMP_TYPE_PARAMETER_PROBLEM:
165 			return B_NET_ERROR_PARAMETER_PROBLEM;
166 
167 		case ICMP_TYPE_REDIRECT:
168 			return B_NET_ERROR_REDIRECT_HOST;
169 
170 		case ICMP_TYPE_SOURCE_QUENCH:
171 			return B_NET_ERROR_QUENCH;
172 
173 		case ICMP_TYPE_TIME_EXCEEDED:
174 			switch (code) {
175 				case ICMP_CODE_TIME_EXCEEDED_IN_TRANSIT:
176 					return B_NET_ERROR_TRANSIT_TIME_EXCEEDED;
177 				case ICMP_CODE_REASSEMBLY_TIME_EXCEEDED:
178 					return B_NET_ERROR_REASSEMBLY_TIME_EXCEEDED;
179 			}
180 			break;
181 
182 		default:
183 			break;
184 	}
185 
186 	return (net_error)0;
187 }
188 
189 
190 static void
191 net_error_to_icmp(net_error error, uint8& type, uint8& code)
192 {
193 	switch (error) {
194 		// redirect
195 		case B_NET_ERROR_REDIRECT_HOST:
196 			type = ICMP_TYPE_REDIRECT;
197 			code = ICMP_CODE_REDIRECT_HOST;
198 			break;
199 
200 		// unreach
201 		case B_NET_ERROR_UNREACH_NET:
202 			type = ICMP_TYPE_UNREACH;
203 			code = ICMP_CODE_NET_UNREACH;
204 			break;
205 		case B_NET_ERROR_UNREACH_HOST:
206 			type = ICMP_TYPE_UNREACH;
207 			code = ICMP_CODE_HOST_UNREACH;
208 			break;
209 		case B_NET_ERROR_UNREACH_PROTOCOL:
210 			type = ICMP_TYPE_UNREACH;
211 			code = ICMP_CODE_PROTOCOL_UNREACH;
212 			break;
213 		case B_NET_ERROR_UNREACH_PORT:
214 			type = ICMP_TYPE_UNREACH;
215 			code = ICMP_CODE_PORT_UNREACH;
216 			break;
217 		case B_NET_ERROR_MESSAGE_SIZE:
218 			type = ICMP_TYPE_UNREACH;
219 			code = ICMP_CODE_FRAGMENTATION_NEEDED;
220 			break;
221 
222 		// time exceeded
223 		case B_NET_ERROR_TRANSIT_TIME_EXCEEDED:
224 			type = ICMP_TYPE_TIME_EXCEEDED;
225 			code = ICMP_CODE_TIME_EXCEEDED_IN_TRANSIT;
226 			break;
227 		case B_NET_ERROR_REASSEMBLY_TIME_EXCEEDED:
228 			type = ICMP_TYPE_TIME_EXCEEDED;
229 			code = ICMP_CODE_REASSEMBLY_TIME_EXCEEDED;
230 			break;
231 
232 		// other
233 		case B_NET_ERROR_PARAMETER_PROBLEM:
234 			type = ICMP_TYPE_PARAMETER_PROBLEM;
235 			code = 0;
236 			break;
237 		case B_NET_ERROR_QUENCH:
238 			type = ICMP_TYPE_SOURCE_QUENCH;
239 			code = 0;
240 			break;
241 	}
242 }
243 
244 
245 // #pragma mark - module API
246 
247 
248 net_protocol*
249 icmp_init_protocol(net_socket* socket)
250 {
251 	icmp_protocol* protocol = new(std::nothrow) icmp_protocol;
252 	if (protocol == NULL)
253 		return NULL;
254 
255 	return protocol;
256 }
257 
258 
259 status_t
260 icmp_uninit_protocol(net_protocol* protocol)
261 {
262 	delete protocol;
263 	return B_OK;
264 }
265 
266 
267 status_t
268 icmp_open(net_protocol* protocol)
269 {
270 	return B_OK;
271 }
272 
273 
274 status_t
275 icmp_close(net_protocol* protocol)
276 {
277 	return B_OK;
278 }
279 
280 
281 status_t
282 icmp_free(net_protocol* protocol)
283 {
284 	return B_OK;
285 }
286 
287 
288 status_t
289 icmp_connect(net_protocol* protocol, const struct sockaddr* address)
290 {
291 	return B_ERROR;
292 }
293 
294 
295 status_t
296 icmp_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
297 {
298 	return B_NOT_SUPPORTED;
299 }
300 
301 
302 status_t
303 icmp_control(net_protocol* protocol, int level, int option, void* value,
304 	size_t* _length)
305 {
306 	return protocol->next->module->control(protocol->next, level, option,
307 		value, _length);
308 }
309 
310 
311 status_t
312 icmp_getsockopt(net_protocol* protocol, int level, int option, void* value,
313 	int* length)
314 {
315 	return protocol->next->module->getsockopt(protocol->next, level, option,
316 		value, length);
317 }
318 
319 
320 status_t
321 icmp_setsockopt(net_protocol* protocol, int level, int option,
322 	const void* value, int length)
323 {
324 	return protocol->next->module->setsockopt(protocol->next, level, option,
325 		value, length);
326 }
327 
328 
329 status_t
330 icmp_bind(net_protocol* protocol, const struct sockaddr* address)
331 {
332 	return B_ERROR;
333 }
334 
335 
336 status_t
337 icmp_unbind(net_protocol* protocol, struct sockaddr* address)
338 {
339 	return B_ERROR;
340 }
341 
342 
343 status_t
344 icmp_listen(net_protocol* protocol, int count)
345 {
346 	return B_NOT_SUPPORTED;
347 }
348 
349 
350 status_t
351 icmp_shutdown(net_protocol* protocol, int direction)
352 {
353 	return B_NOT_SUPPORTED;
354 }
355 
356 
357 status_t
358 icmp_send_data(net_protocol* protocol, net_buffer* buffer)
359 {
360 	return protocol->next->module->send_data(protocol->next, buffer);
361 }
362 
363 
364 status_t
365 icmp_send_routed_data(net_protocol* protocol, struct net_route* route,
366 	net_buffer* buffer)
367 {
368 	return protocol->next->module->send_routed_data(protocol->next, route,
369 		buffer);
370 }
371 
372 
373 ssize_t
374 icmp_send_avail(net_protocol* protocol)
375 {
376 	return B_ERROR;
377 }
378 
379 
380 status_t
381 icmp_read_data(net_protocol* protocol, size_t numBytes, uint32 flags,
382 	net_buffer** _buffer)
383 {
384 	return B_ERROR;
385 }
386 
387 
388 ssize_t
389 icmp_read_avail(net_protocol* protocol)
390 {
391 	return B_ERROR;
392 }
393 
394 
395 struct net_domain*
396 icmp_get_domain(net_protocol* protocol)
397 {
398 	return protocol->next->module->get_domain(protocol->next);
399 }
400 
401 
402 size_t
403 icmp_get_mtu(net_protocol* protocol, const struct sockaddr* address)
404 {
405 	return protocol->next->module->get_mtu(protocol->next, address);
406 }
407 
408 
409 status_t
410 icmp_receive_data(net_buffer* buffer)
411 {
412 	TRACE("ICMP received some data, buffer length %lu\n", buffer->size);
413 
414 	net_domain* domain = get_domain(buffer);
415 	if (domain == NULL)
416 		return B_ERROR;
417 
418 	NetBufferHeaderReader<icmp_header> bufferHeader(buffer);
419 	if (bufferHeader.Status() < B_OK)
420 		return bufferHeader.Status();
421 
422 	icmp_header& header = bufferHeader.Data();
423 	uint8 type = header.type;
424 
425 	TRACE("  got type %u, code %u, checksum %u\n", header.type, header.code,
426 		ntohs(header.checksum));
427 	TRACE("  computed checksum: %ld\n",
428 		gBufferModule->checksum(buffer, 0, buffer->size, true));
429 
430 	if (gBufferModule->checksum(buffer, 0, buffer->size, true) != 0)
431 		return B_BAD_DATA;
432 
433 	switch (type) {
434 		case ICMP_TYPE_ECHO_REPLY:
435 			break;
436 
437 		case ICMP_TYPE_ECHO_REQUEST:
438 		{
439 			net_domain* domain = get_domain(buffer);
440 			if (domain == NULL)
441 				break;
442 
443 			if (buffer->interface_address != NULL) {
444 				// We only reply to echo requests of our local interface; we
445 				// don't reply to broadcast requests
446 				if (!domain->address_module->equal_addresses(
447 						buffer->interface_address->local, buffer->destination))
448 					break;
449 			}
450 
451 			net_buffer* reply = gBufferModule->duplicate(buffer);
452 			if (reply == NULL)
453 				return B_NO_MEMORY;
454 
455 			gBufferModule->swap_addresses(reply);
456 
457 			// There already is an ICMP header, and we'll reuse it
458 			NetBufferHeaderReader<icmp_header> newHeader(reply);
459 
460 			newHeader->type = type == ICMP_TYPE_ECHO_REPLY;
461 			newHeader->code = 0;
462 			newHeader->checksum = 0;
463 
464 			newHeader.Sync();
465 
466 			*ICMPChecksumField(reply) = gBufferModule->checksum(reply, 0,
467 					reply->size, true);
468 
469 			status_t status = domain->module->send_data(NULL, reply);
470 			if (status < B_OK) {
471 				gBufferModule->free(reply);
472 				return status;
473 			}
474 			break;
475 		}
476 
477 		case ICMP_TYPE_UNREACH:
478 		case ICMP_TYPE_SOURCE_QUENCH:
479 		case ICMP_TYPE_PARAMETER_PROBLEM:
480 		case ICMP_TYPE_TIME_EXCEEDED:
481 		{
482 			net_domain* domain = get_domain(buffer);
483 			if (domain == NULL)
484 				break;
485 
486 			// Deliver the error to the domain protocol which will
487 			// propagate the error to the upper protocols
488 			net_error error = icmp_to_net_error(header.type, header.code);
489 			if (error != 0) {
490 				bufferHeader.Remove();
491 				return domain->module->error_received(error, buffer);
492 			}
493 			break;
494 		}
495 
496 		case ICMP_TYPE_REDIRECT:
497 			// TODO: Update the routing table
498 		case ICMP_TYPE_TIMESTAMP_REQUEST:
499 		case ICMP_TYPE_TIMESTAMP_REPLY:
500 		case ICMP_TYPE_INFO_REQUEST:
501 		case ICMP_TYPE_INFO_REPLY:
502 		default:
503 			// RFC 1122 3.2.2:
504 			// Unknown ICMP messages are silently discarded
505 			dprintf("ICMP: received unhandled type %u, code %u\n", header.type,
506 				header.code);
507 			break;
508 	}
509 
510 	gBufferModule->free(buffer);
511 	return B_OK;
512 }
513 
514 
515 status_t
516 icmp_error_received(net_error code, net_buffer* data)
517 {
518 	return B_ERROR;
519 }
520 
521 
522 /*!	Sends an ICMP error message to the source of the \a buffer causing the
523 	error.
524 */
525 status_t
526 icmp_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
527 	net_error_data* errorData)
528 {
529 	TRACE("icmp_error_reply(code %s)\n", net_error_to_string(error));
530 
531 	uint8 icmpType = 0;
532 	uint8 icmpCode = 0;
533 	net_error_to_icmp(error, icmpType, icmpCode);
534 
535 	TRACE("  icmp type %u, code %u\n", icmpType, icmpCode);
536 
537 	ipv4_header header;
538 	if (gBufferModule->restore_header(buffer, 0, &header, sizeof(ipv4_header))
539 			!= B_OK)
540 		return B_BAD_VALUE;
541 
542 	// Check if we actually have an IPv4 header now
543 	if (header.version != IPV4_VERSION
544 		|| header.HeaderLength() < sizeof(ipv4_header)) {
545 		TRACE("  no IPv4 header found\n");
546 		return B_BAD_VALUE;
547 	}
548 
549 	// RFC 1122 3.2.2:
550 	// ICMP error message should not be sent on reception of
551 	// an ICMP error message,
552 	if (header.protocol == IPPROTO_ICMP) {
553 		uint8 type;
554 		if (gBufferModule->restore_header(buffer, header.HeaderLength(), &type,
555 				1) != B_OK || is_icmp_error(type))
556 			return B_ERROR;
557 	}
558 
559 	// a datagram to an IP multicast or broadcast address,
560 	if ((buffer->msg_flags & (MSG_BCAST | MSG_MCAST)) != 0)
561 		return B_ERROR;
562 
563 	// a non-initial fragment
564 	if ((header.FragmentOffset() & IP_FRAGMENT_OFFSET_MASK) != 0)
565 		return B_ERROR;
566 
567 	net_buffer* reply = gBufferModule->create(256);
568 	if (reply == NULL)
569 		return B_NO_MEMORY;
570 
571 	if (buffer->destination->sa_family == AF_INET) {
572 		memcpy(reply->source, buffer->destination, buffer->destination->sa_len);
573 		memcpy(reply->destination, buffer->source, buffer->source->sa_len);
574 	} else {
575 		fill_sockaddr_in((sockaddr_in*)reply->source, header.destination);
576 		fill_sockaddr_in((sockaddr_in*)reply->destination, header.source);
577 	}
578 
579 	// Now prepare the ICMP header
580 
581 	NetBufferPrepend<icmp_header> icmpHeader(reply);
582 	icmpHeader->type = icmpType;
583 	icmpHeader->code = icmpCode;
584 	icmpHeader->zero = 0;
585 	icmpHeader->checksum = 0;
586 
587 	if (errorData != NULL) {
588 		switch (error) {
589 			case B_NET_ERROR_REDIRECT_HOST:
590 			{
591 				sockaddr_in& gateway = (sockaddr_in&)errorData->gateway;
592 				icmpHeader->redirect.gateway = gateway.sin_addr.s_addr;
593 				break;
594 			}
595 			case B_NET_ERROR_PARAMETER_PROBLEM:
596 				icmpHeader->parameter_problem.pointer = errorData->error_offset;
597 				break;
598 			case B_NET_ERROR_MESSAGE_SIZE:
599 				icmpHeader->path_mtu.next_mtu = errorData->mtu;
600 				break;
601 
602 			default:
603 				break;
604 		}
605 	}
606 
607 	icmpHeader.Sync();
608 
609 	// Append IP header + 8 byte of the original datagram
610 	status_t status = gBufferModule->append_restored_header(reply, buffer, 0,
611 		std::min(header.HeaderLength() + 8, (int)header.TotalLength()));
612 	if (status == B_OK) {
613 		net_domain* domain = get_domain(buffer);
614 		if (domain == NULL)
615 			return B_ERROR;
616 
617 		*ICMPChecksumField(reply)
618 			= gBufferModule->checksum(reply, 0, reply->size, true);
619 
620 		reply->protocol = IPPROTO_ICMP;
621 
622 		TRACE("  send ICMP message %p to %s\n", reply, AddressString(
623 				domain->address_module, reply->destination, true).Data());
624 
625 		status = domain->module->send_data(NULL, reply);
626 	}
627 	if (status != B_OK)
628 		gBufferModule->free(reply);
629 
630 	return status;
631 }
632 
633 
634 //	#pragma mark -
635 
636 
637 static status_t
638 icmp_std_ops(int32 op, ...)
639 {
640 	switch (op) {
641 		case B_MODULE_INIT:
642 		{
643 			sStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM,
644 				IPPROTO_ICMP,
645 				"network/protocols/icmp/v1",
646 				"network/protocols/ipv4/v1",
647 				NULL);
648 
649 			sStackModule->register_domain_receiving_protocol(AF_INET,
650 				IPPROTO_ICMP, "network/protocols/icmp/v1");
651 			return B_OK;
652 		}
653 
654 		case B_MODULE_UNINIT:
655 			return B_OK;
656 
657 		default:
658 			return B_ERROR;
659 	}
660 }
661 
662 
663 net_protocol_module_info sICMPModule = {
664 	{
665 		"network/protocols/icmp/v1",
666 		0,
667 		icmp_std_ops
668 	},
669 	NET_PROTOCOL_ATOMIC_MESSAGES,
670 
671 	icmp_init_protocol,
672 	icmp_uninit_protocol,
673 	icmp_open,
674 	icmp_close,
675 	icmp_free,
676 	icmp_connect,
677 	icmp_accept,
678 	icmp_control,
679 	icmp_getsockopt,
680 	icmp_setsockopt,
681 	icmp_bind,
682 	icmp_unbind,
683 	icmp_listen,
684 	icmp_shutdown,
685 	icmp_send_data,
686 	icmp_send_routed_data,
687 	icmp_send_avail,
688 	icmp_read_data,
689 	icmp_read_avail,
690 	icmp_get_domain,
691 	icmp_get_mtu,
692 	icmp_receive_data,
693 	NULL,		// deliver_data()
694 	icmp_error_received,
695 	icmp_error_reply,
696 	NULL,		// add_ancillary_data()
697 	NULL,		// process_ancillary_data()
698 	NULL,		// process_ancillary_data_no_container()
699 	NULL,		// send_data_no_buffer()
700 	NULL		// read_data_no_buffer()
701 };
702 
703 module_dependency module_dependencies[] = {
704 	{NET_STACK_MODULE_NAME, (module_info**)&sStackModule},
705 	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
706 	{}
707 };
708 
709 module_info* modules[] = {
710 	(module_info*)&sICMPModule,
711 	NULL
712 };
713