Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
icmp.c
Go to the documentation of this file.
00001 /** 00002 * @file icmp.c 00003 * @brief ICMP (Internet Control Message Protocol) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL ICMP_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include <string.h> 00034 #include "core/net.h" 00035 #include "core/ip.h" 00036 #include "ipv4/ipv4.h" 00037 #include "ipv4/icmp.h" 00038 #include "mibs/mib2_module.h" 00039 #include "debug.h" 00040 00041 //Check TCP/IP stack configuration 00042 #if (IPV4_SUPPORT == ENABLED) 00043 00044 00045 /** 00046 * @brief Incoming ICMP message processing 00047 * @param[in] interface Underlying network interface 00048 * @param[in] srcIpAddr Source IPv4 address 00049 * @param[in] buffer Multi-part buffer containing the incoming ICMP message 00050 * @param[in] offset Offset to the first byte of the ICMP message 00051 **/ 00052 00053 void icmpProcessMessage(NetInterface *interface, 00054 Ipv4Addr srcIpAddr, const NetBuffer *buffer, size_t offset) 00055 { 00056 size_t length; 00057 IcmpHeader *header; 00058 00059 //Total number of ICMP messages which the entity received 00060 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInMsgs, 1); 00061 00062 //Retrieve the length of the ICMP message 00063 length = netBufferGetLength(buffer) - offset; 00064 00065 //Ensure the message length is correct 00066 if(length < sizeof(IcmpHeader)) 00067 { 00068 //Number of ICMP messages which the entity received but determined 00069 //as having ICMP-specific errors 00070 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInErrors, 1); 00071 //Silently discard incoming message 00072 return; 00073 } 00074 00075 //Point to the ICMP message header 00076 header = netBufferAt(buffer, offset); 00077 //Sanity check 00078 if(header == NULL) 00079 return; 00080 00081 //Debug message 00082 TRACE_INFO("ICMP message received (%" PRIuSIZE " bytes)...\r\n", length); 00083 //Dump message contents for debugging purpose 00084 icmpDumpMessage(header); 00085 00086 //Verify checksum value 00087 if(ipCalcChecksumEx(buffer, offset, length) != 0x0000) 00088 { 00089 //Debug message 00090 TRACE_WARNING("Wrong ICMP header checksum!\r\n"); 00091 //Number of ICMP messages which the entity received but determined 00092 //as having ICMP-specific errors 00093 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInErrors, 1); 00094 //Drop incoming message 00095 return; 00096 } 00097 00098 //Check the type of ICMP message 00099 switch(header->type) 00100 { 00101 //Echo Request? 00102 case ICMP_TYPE_ECHO_REQUEST: 00103 //Process Echo Request message 00104 icmpProcessEchoRequest(interface, srcIpAddr, buffer, offset); 00105 break; 00106 //Unknown type? 00107 default: 00108 //Debug message 00109 TRACE_WARNING("Unknown ICMP message type!\r\n"); 00110 //Discard incoming ICMP message 00111 break; 00112 } 00113 } 00114 00115 00116 /** 00117 * @brief Echo Request message processing 00118 * @param[in] interface Underlying network interface 00119 * @param[in] srcIpAddr Source IPv4 address 00120 * @param[in] request Multi-part buffer containing the incoming Echo Request message 00121 * @param[in] requestOffset Offset to the first byte of the Echo Request message 00122 **/ 00123 00124 void icmpProcessEchoRequest(NetInterface *interface, 00125 Ipv4Addr srcIpAddr, const NetBuffer *request, size_t requestOffset) 00126 { 00127 error_t error; 00128 size_t requestLength; 00129 size_t replyOffset; 00130 size_t replyLength; 00131 NetBuffer *reply; 00132 IcmpEchoMessage *requestHeader; 00133 IcmpEchoMessage *replyHeader; 00134 Ipv4PseudoHeader pseudoHeader; 00135 00136 //Number of ICMP Echo Request messages received 00137 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpInEchos, 1); 00138 00139 //Retrieve the length of the Echo Request message 00140 requestLength = netBufferGetLength(request) - requestOffset; 00141 00142 //Ensure the packet length is correct 00143 if(requestLength < sizeof(IcmpEchoMessage)) 00144 return; 00145 00146 //Point to the Echo Request header 00147 requestHeader = netBufferAt(request, requestOffset); 00148 //Sanity check 00149 if(requestHeader == NULL) 00150 return; 00151 00152 //Debug message 00153 TRACE_INFO("ICMP Echo Request message received (%" PRIuSIZE " bytes)...\r\n", requestLength); 00154 //Dump message contents for debugging purpose 00155 icmpDumpEchoMessage(requestHeader); 00156 00157 //Allocate memory to hold the Echo Reply message 00158 reply = ipAllocBuffer(sizeof(IcmpEchoMessage), &replyOffset); 00159 //Failed to allocate memory? 00160 if(reply == NULL) 00161 return; 00162 00163 //Point to the Echo Reply header 00164 replyHeader = netBufferAt(reply, replyOffset); 00165 00166 //Format Echo Reply header 00167 replyHeader->type = ICMP_TYPE_ECHO_REPLY; 00168 replyHeader->code = 0; 00169 replyHeader->checksum = 0; 00170 replyHeader->identifier = requestHeader->identifier; 00171 replyHeader->sequenceNumber = requestHeader->sequenceNumber; 00172 00173 //Point to the first data byte 00174 requestOffset += sizeof(IcmpEchoMessage); 00175 requestLength -= sizeof(IcmpEchoMessage); 00176 00177 //Copy data 00178 error = netBufferConcat(reply, request, requestOffset, requestLength); 00179 00180 //Check status code 00181 if(!error) 00182 { 00183 //Get the length of the resulting message 00184 replyLength = netBufferGetLength(reply) - replyOffset; 00185 //Calculate ICMP header checksum 00186 replyHeader->checksum = ipCalcChecksumEx(reply, replyOffset, replyLength); 00187 00188 //Format IPv4 pseudo header 00189 pseudoHeader.srcAddr = interface->ipv4Context.addr; 00190 pseudoHeader.destAddr = srcIpAddr; 00191 pseudoHeader.reserved = 0; 00192 pseudoHeader.protocol = IPV4_PROTOCOL_ICMP; 00193 pseudoHeader.length = htons(replyLength); 00194 00195 //Total number of ICMP messages which this entity attempted to send 00196 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutMsgs, 1); 00197 //Number of ICMP Echo Reply messages sent 00198 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutEchoReps, 1); 00199 00200 //Debug message 00201 TRACE_INFO("Sending ICMP Echo Reply message (%" PRIuSIZE " bytes)...\r\n", replyLength); 00202 //Dump message contents for debugging purpose 00203 icmpDumpEchoMessage(replyHeader); 00204 00205 //Send Echo Reply message 00206 ipv4SendDatagram(interface, &pseudoHeader, reply, replyOffset, IPV4_DEFAULT_TTL); 00207 } 00208 00209 //Free previously allocated memory block 00210 netBufferFree(reply); 00211 } 00212 00213 00214 /** 00215 * @brief Send an ICMP Error message 00216 * @param[in] interface Underlying network interface 00217 * @param[in] type Message type 00218 * @param[in] code Specific message code 00219 * @param[in] parameter Specific message parameter 00220 * @param[in] ipPacket Multi-part buffer that holds the invoking IPv4 packet 00221 * @param[in] ipPacketOffset Offset to the first byte of the IPv4 packet 00222 * @return Error code 00223 **/ 00224 00225 error_t icmpSendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, 00226 uint8_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset) 00227 { 00228 error_t error; 00229 size_t offset; 00230 size_t length; 00231 Ipv4Header *ipHeader; 00232 NetBuffer *icmpMessage; 00233 IcmpErrorMessage *icmpHeader; 00234 Ipv4PseudoHeader pseudoHeader; 00235 00236 //Retrieve the length of the invoking IPv4 packet 00237 length = netBufferGetLength(ipPacket) - ipPacketOffset; 00238 00239 //Check the length of the IPv4 packet 00240 if(length < sizeof(Ipv4Header)) 00241 return ERROR_INVALID_LENGTH; 00242 00243 //Point to the header of the invoking packet 00244 ipHeader = netBufferAt(ipPacket, ipPacketOffset); 00245 //Sanity check 00246 if(ipHeader == NULL) 00247 return ERROR_FAILURE; 00248 00249 //Never respond to a packet destined to a broadcast or a multicast address 00250 if(ipv4IsBroadcastAddr(interface, ipHeader->destAddr) || 00251 ipv4IsMulticastAddr(ipHeader->destAddr)) 00252 { 00253 //Report an error 00254 return ERROR_INVALID_ADDRESS; 00255 } 00256 00257 //Length of the data that will be returned along with the ICMP header 00258 length = MIN(length, (size_t) ipHeader->headerLength * 4 + 8); 00259 00260 //Allocate a memory buffer to hold the ICMP message 00261 icmpMessage = ipAllocBuffer(sizeof(IcmpErrorMessage), &offset); 00262 //Failed to allocate memory? 00263 if(icmpMessage == NULL) 00264 return ERROR_OUT_OF_MEMORY; 00265 00266 //Point to the ICMP header 00267 icmpHeader = netBufferAt(icmpMessage, offset); 00268 00269 //Format ICMP message 00270 icmpHeader->type = type; 00271 icmpHeader->code = code; 00272 icmpHeader->checksum = 0; 00273 icmpHeader->parameter = parameter; 00274 icmpHeader->unused = 0; 00275 00276 //Copy the IP header and the first 8 bytes of the original datagram data 00277 error = netBufferConcat(icmpMessage, ipPacket, ipPacketOffset, length); 00278 00279 //Check status code 00280 if(!error) 00281 { 00282 //Get the length of the resulting message 00283 length = netBufferGetLength(icmpMessage) - offset; 00284 //Message checksum calculation 00285 icmpHeader->checksum = ipCalcChecksumEx(icmpMessage, offset, length); 00286 00287 //Format IPv4 pseudo header 00288 pseudoHeader.srcAddr = ipHeader->destAddr; 00289 pseudoHeader.destAddr = ipHeader->srcAddr; 00290 pseudoHeader.reserved = 0; 00291 pseudoHeader.protocol = IPV4_PROTOCOL_ICMP; 00292 pseudoHeader.length = htons(length); 00293 00294 //Total number of ICMP messages which this entity attempted to send 00295 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutMsgs, 1); 00296 00297 //Check ICMP message type 00298 if(code == ICMP_TYPE_DEST_UNREACHABLE) 00299 { 00300 //Number of ICMP Destination Unreachable messages sent 00301 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutDestUnreachs, 1); 00302 } 00303 else if(code == ICMP_TYPE_SOURCE_QUENCH) 00304 { 00305 //Number of ICMP Source Quench messages sent 00306 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutSrcQuenchs, 1); 00307 } 00308 else if(code == ICMP_TYPE_REDIRECT) 00309 { 00310 //Number of ICMP Redirect messages sent 00311 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutRedirects, 1); 00312 } 00313 else if(code == ICMP_TYPE_TIME_EXCEEDED) 00314 { 00315 //Number of ICMP Time Exceeded messages sent 00316 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutTimeExcds, 1); 00317 } 00318 else if(code == ICMP_TYPE_PARAM_PROBLEM) 00319 { 00320 //Number of ICMP Parameter Problem messages sent 00321 MIB2_INC_COUNTER32(mib2Base.icmpGroup.icmpOutParmProbs, 1); 00322 } 00323 00324 //Debug message 00325 TRACE_INFO("Sending ICMP Error message (%" PRIuSIZE " bytes)...\r\n", length); 00326 //Dump message contents for debugging purpose 00327 icmpDumpErrorMessage(icmpHeader); 00328 00329 //Send ICMP Error message 00330 error = ipv4SendDatagram(interface, &pseudoHeader, 00331 icmpMessage, offset, IPV4_DEFAULT_TTL); 00332 } 00333 00334 //Free previously allocated memory 00335 netBufferFree(icmpMessage); 00336 00337 //Return status code 00338 return error; 00339 } 00340 00341 00342 /** 00343 * @brief Dump ICMP message for debugging purpose 00344 * @param[in] message Pointer to the ICMP message 00345 **/ 00346 00347 void icmpDumpMessage(const IcmpHeader *message) 00348 { 00349 //Dump ICMP message 00350 TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type); 00351 TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code); 00352 TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum)); 00353 } 00354 00355 00356 /** 00357 * @brief Dump ICMP Echo Request or Echo Reply message 00358 * @param[in] message Pointer to the ICMP message 00359 **/ 00360 00361 void icmpDumpEchoMessage(const IcmpEchoMessage *message) 00362 { 00363 //Dump ICMP message 00364 TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type); 00365 TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code); 00366 TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum)); 00367 TRACE_DEBUG(" Identifier = 0x%04" PRIX16 "\r\n", ntohs(message->identifier)); 00368 TRACE_DEBUG(" Sequence Number = 0x%04" PRIX16 "\r\n", ntohs(message->sequenceNumber)); 00369 } 00370 00371 00372 /** 00373 * @brief Dump generic ICMP Error message 00374 * @param[in] message Pointer to the ICMP message 00375 **/ 00376 00377 void icmpDumpErrorMessage(const IcmpErrorMessage *message) 00378 { 00379 //Dump ICMP message 00380 TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type); 00381 TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code); 00382 TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum)); 00383 TRACE_DEBUG(" Parameter = %" PRIu8 "\r\n", message->parameter); 00384 } 00385 00386 #endif 00387
Generated on Tue Jul 12 2022 17:10:13 by
