1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * icmp.c - convenience functions for translating ICMP and ICMPv6 packets. 17 */ 18 19 #include <netinet/in.h> 20 #include <netinet/ip_icmp.h> 21 #include <netinet/icmp6.h> 22 #include <linux/icmp.h> 23 24 #include "logging.h" 25 #include "icmp.h" 26 27 /* function: icmp_guess_ttl 28 * Guesses the number of hops a received packet has traversed based on its TTL. 29 * ttl - the ttl of the received packet. 30 */ 31 uint8_t icmp_guess_ttl(uint8_t ttl) { 32 if (ttl > 128) { 33 return 255 - ttl; 34 } else if (ttl > 64) { 35 return 128 - ttl; 36 } else if (ttl > 32) { 37 return 64 - ttl; 38 } else { 39 return 32 - ttl; 40 } 41 } 42 43 /* function: is_icmp_error 44 * Determines whether an ICMP type is an error message. 45 * type: the ICMP type 46 */ 47 int is_icmp_error(uint8_t type) { 48 return type == 3 || type == 11 || type == 12; 49 } 50 51 /* function: is_icmp6_error 52 * Determines whether an ICMPv6 type is an error message. 53 * type: the ICMPv6 type 54 */ 55 int is_icmp6_error(uint8_t type) { 56 return type < 128; 57 } 58 59 /* function: icmp_to_icmp6_type 60 * Maps ICMP types to ICMPv6 types. Partial implementation of RFC 6145, section 4.2. 61 * type - the ICMPv6 type 62 */ 63 uint8_t icmp_to_icmp6_type(uint8_t type, uint8_t code) { 64 switch (type) { 65 case ICMP_ECHO: 66 return ICMP6_ECHO_REQUEST; 67 68 case ICMP_ECHOREPLY: 69 return ICMP6_ECHO_REPLY; 70 71 case ICMP_TIME_EXCEEDED: 72 return ICMP6_TIME_EXCEEDED; 73 74 case ICMP_DEST_UNREACH: 75 // These two types need special translation which we don't support yet. 76 if (code != ICMP_UNREACH_PROTOCOL && code != ICMP_UNREACH_NEEDFRAG) { 77 return ICMP6_DST_UNREACH; 78 } 79 } 80 81 // We don't understand this ICMP type. Return parameter problem so the caller will bail out. 82 logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_type: unhandled ICMP type %d", type); 83 return ICMP6_PARAM_PROB; 84 } 85 86 /* function: icmp_to_icmp6_code 87 * Maps ICMP codes to ICMPv6 codes. Partial implementation of RFC 6145, section 4.2. 88 * type - the ICMP type 89 * code - the ICMP code 90 */ 91 uint8_t icmp_to_icmp6_code(uint8_t type, uint8_t code) { 92 switch (type) { 93 case ICMP_ECHO: 94 case ICMP_ECHOREPLY: 95 return 0; 96 97 case ICMP_TIME_EXCEEDED: 98 return code; 99 100 case ICMP_DEST_UNREACH: 101 switch (code) { 102 case ICMP_UNREACH_NET: 103 case ICMP_UNREACH_HOST: 104 return ICMP6_DST_UNREACH_NOROUTE; 105 106 case ICMP_UNREACH_PORT: 107 return ICMP6_DST_UNREACH_NOPORT; 108 109 case ICMP_UNREACH_NET_PROHIB: 110 case ICMP_UNREACH_HOST_PROHIB: 111 case ICMP_UNREACH_FILTER_PROHIB: 112 case ICMP_UNREACH_PRECEDENCE_CUTOFF: 113 return ICMP6_DST_UNREACH_ADMIN; 114 115 // Otherwise, we don't understand this ICMP type/code combination. Fall through. 116 } 117 } 118 logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_code: unhandled ICMP type/code %d/%d", type, code); 119 return 0; 120 } 121 122 /* function: icmp6_to_icmp_type 123 * Maps ICMPv6 types to ICMP types. Partial implementation of RFC 6145, section 5.2. 124 * type - the ICMP type 125 */ 126 uint8_t icmp6_to_icmp_type(uint8_t type, uint8_t code) { 127 switch (type) { 128 case ICMP6_ECHO_REQUEST: 129 return ICMP_ECHO; 130 131 case ICMP6_ECHO_REPLY: 132 return ICMP_ECHOREPLY; 133 134 case ICMP6_DST_UNREACH: 135 return ICMP_DEST_UNREACH; 136 137 case ICMP6_TIME_EXCEEDED: 138 return ICMP_TIME_EXCEEDED; 139 } 140 141 // We don't understand this ICMP type. Return parameter problem so the caller will bail out. 142 logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_type: unhandled ICMP type/code %d/%d", type, code); 143 return ICMP_PARAMETERPROB; 144 } 145 146 /* function: icmp6_to_icmp_code 147 * Maps ICMPv6 codes to ICMP codes. Partial implementation of RFC 6145, section 5.2. 148 * type - the ICMPv6 type 149 * code - the ICMPv6 code 150 */ 151 uint8_t icmp6_to_icmp_code(uint8_t type, uint8_t code) { 152 switch (type) { 153 case ICMP6_ECHO_REQUEST: 154 case ICMP6_ECHO_REPLY: 155 case ICMP6_TIME_EXCEEDED: 156 return code; 157 158 case ICMP6_DST_UNREACH: 159 switch (code) { 160 case ICMP6_DST_UNREACH_NOROUTE: 161 return ICMP_UNREACH_HOST; 162 163 case ICMP6_DST_UNREACH_ADMIN: 164 return ICMP_UNREACH_HOST_PROHIB; 165 166 case ICMP6_DST_UNREACH_BEYONDSCOPE: 167 return ICMP_UNREACH_HOST; 168 169 case ICMP6_DST_UNREACH_ADDR: 170 return ICMP_HOST_UNREACH; 171 172 case ICMP6_DST_UNREACH_NOPORT: 173 return ICMP_UNREACH_PORT; 174 175 // Otherwise, we don't understand this ICMPv6 type/code combination. Fall through. 176 } 177 } 178 179 logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_code: unhandled ICMP type/code %d/%d", type, code); 180 return 0; 181 } 182