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