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