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