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
43struct 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
68typedef 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
77struct icmp_protocol : net_protocol {
78};
79
80
81net_buffer_module_info* gBufferModule;
82static net_stack_module_info* sStackModule;
83
84
85#ifdef TRACE_ICMP
86
87
88static const char*
89net_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
113static net_domain*
114get_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
129static void
130fill_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
139static bool
140is_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
150static net_error
151icmp_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
195static void
196net_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
253net_protocol*
254icmp_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
264status_t
265icmp_uninit_protocol(net_protocol* protocol)
266{
267	delete protocol;
268	return B_OK;
269}
270
271
272status_t
273icmp_open(net_protocol* protocol)
274{
275	return B_OK;
276}
277
278
279status_t
280icmp_close(net_protocol* protocol)
281{
282	return B_OK;
283}
284
285
286status_t
287icmp_free(net_protocol* protocol)
288{
289	return B_OK;
290}
291
292
293status_t
294icmp_connect(net_protocol* protocol, const struct sockaddr* address)
295{
296	return B_ERROR;
297}
298
299
300status_t
301icmp_accept(net_protocol* protocol, struct net_socket** _acceptedSocket)
302{
303	return B_NOT_SUPPORTED;
304}
305
306
307status_t
308icmp_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
316status_t
317icmp_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
325status_t
326icmp_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
334status_t
335icmp_bind(net_protocol* protocol, const struct sockaddr* address)
336{
337	return B_ERROR;
338}
339
340
341status_t
342icmp_unbind(net_protocol* protocol, struct sockaddr* address)
343{
344	return B_ERROR;
345}
346
347
348status_t
349icmp_listen(net_protocol* protocol, int count)
350{
351	return B_NOT_SUPPORTED;
352}
353
354
355status_t
356icmp_shutdown(net_protocol* protocol, int direction)
357{
358	return B_NOT_SUPPORTED;
359}
360
361
362status_t
363icmp_send_data(net_protocol* protocol, net_buffer* buffer)
364{
365	return protocol->next->module->send_data(protocol->next, buffer);
366}
367
368
369status_t
370icmp_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
378ssize_t
379icmp_send_avail(net_protocol* protocol)
380{
381	return B_ERROR;
382}
383
384
385status_t
386icmp_read_data(net_protocol* protocol, size_t numBytes, uint32 flags,
387	net_buffer** _buffer)
388{
389	return B_ERROR;
390}
391
392
393ssize_t
394icmp_read_avail(net_protocol* protocol)
395{
396	return B_ERROR;
397}
398
399
400struct net_domain*
401icmp_get_domain(net_protocol* protocol)
402{
403	return protocol->next->module->get_domain(protocol->next);
404}
405
406
407size_t
408icmp_get_mtu(net_protocol* protocol, const struct sockaddr* address)
409{
410	return protocol->next->module->get_mtu(protocol->next, address);
411}
412
413
414status_t
415icmp_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
520status_t
521icmp_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*/
530status_t
531icmp_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
642static status_t
643icmp_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
668net_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
708module_dependency module_dependencies[] = {
709	{NET_STACK_MODULE_NAME, (module_info**)&sStackModule},
710	{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
711	{}
712};
713
714module_info* modules[] = {
715	(module_info*)&sICMPModule,
716	NULL
717};
718