You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.0 KiB
178 lines
5.0 KiB
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* icmp.c - convenience functions for translating ICMP and ICMPv6 packets.
|
|
*/
|
|
|
|
#include <linux/icmp.h>
|
|
#include <netinet/icmp6.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip_icmp.h>
|
|
|
|
#include "icmp.h"
|
|
#include "logging.h"
|
|
|
|
/* function: icmp_guess_ttl
|
|
* Guesses the number of hops a received packet has traversed based on its TTL.
|
|
* ttl - the ttl of the received packet.
|
|
*/
|
|
uint8_t icmp_guess_ttl(uint8_t ttl) {
|
|
if (ttl > 128) {
|
|
return 255 - ttl;
|
|
} else if (ttl > 64) {
|
|
return 128 - ttl;
|
|
} else if (ttl > 32) {
|
|
return 64 - ttl;
|
|
} else {
|
|
return 32 - ttl;
|
|
}
|
|
}
|
|
|
|
/* function: is_icmp_error
|
|
* Determines whether an ICMP type is an error message.
|
|
* type: the ICMP type
|
|
*/
|
|
int is_icmp_error(uint8_t type) { return type == 3 || type == 11 || type == 12; }
|
|
|
|
/* function: is_icmp6_error
|
|
* Determines whether an ICMPv6 type is an error message.
|
|
* type: the ICMPv6 type
|
|
*/
|
|
int is_icmp6_error(uint8_t type) { return type < 128; }
|
|
|
|
/* function: icmp_to_icmp6_type
|
|
* Maps ICMP types to ICMPv6 types. Partial implementation of RFC 6145, section 4.2.
|
|
* type - the ICMPv6 type
|
|
*/
|
|
uint8_t icmp_to_icmp6_type(uint8_t type, uint8_t code) {
|
|
switch (type) {
|
|
case ICMP_ECHO:
|
|
return ICMP6_ECHO_REQUEST;
|
|
|
|
case ICMP_ECHOREPLY:
|
|
return ICMP6_ECHO_REPLY;
|
|
|
|
case ICMP_TIME_EXCEEDED:
|
|
return ICMP6_TIME_EXCEEDED;
|
|
|
|
case ICMP_DEST_UNREACH:
|
|
// These two types need special translation which we don't support yet.
|
|
if (code != ICMP_UNREACH_PROTOCOL && code != ICMP_UNREACH_NEEDFRAG) {
|
|
return ICMP6_DST_UNREACH;
|
|
}
|
|
}
|
|
|
|
// We don't understand this ICMP type. Return parameter problem so the caller will bail out.
|
|
logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_type: unhandled ICMP type %d", type);
|
|
return ICMP6_PARAM_PROB;
|
|
}
|
|
|
|
/* function: icmp_to_icmp6_code
|
|
* Maps ICMP codes to ICMPv6 codes. Partial implementation of RFC 6145, section 4.2.
|
|
* type - the ICMP type
|
|
* code - the ICMP code
|
|
*/
|
|
uint8_t icmp_to_icmp6_code(uint8_t type, uint8_t code) {
|
|
switch (type) {
|
|
case ICMP_ECHO:
|
|
case ICMP_ECHOREPLY:
|
|
return 0;
|
|
|
|
case ICMP_TIME_EXCEEDED:
|
|
return code;
|
|
|
|
case ICMP_DEST_UNREACH:
|
|
switch (code) {
|
|
case ICMP_UNREACH_NET:
|
|
case ICMP_UNREACH_HOST:
|
|
return ICMP6_DST_UNREACH_NOROUTE;
|
|
|
|
case ICMP_UNREACH_PORT:
|
|
return ICMP6_DST_UNREACH_NOPORT;
|
|
|
|
case ICMP_UNREACH_NET_PROHIB:
|
|
case ICMP_UNREACH_HOST_PROHIB:
|
|
case ICMP_UNREACH_FILTER_PROHIB:
|
|
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
|
|
return ICMP6_DST_UNREACH_ADMIN;
|
|
|
|
// Otherwise, we don't understand this ICMP type/code combination. Fall through.
|
|
}
|
|
}
|
|
logmsg_dbg(ANDROID_LOG_DEBUG, "icmp_to_icmp6_code: unhandled ICMP type/code %d/%d", type, code);
|
|
return 0;
|
|
}
|
|
|
|
/* function: icmp6_to_icmp_type
|
|
* Maps ICMPv6 types to ICMP types. Partial implementation of RFC 6145, section 5.2.
|
|
* type - the ICMP type
|
|
*/
|
|
uint8_t icmp6_to_icmp_type(uint8_t type, uint8_t code) {
|
|
switch (type) {
|
|
case ICMP6_ECHO_REQUEST:
|
|
return ICMP_ECHO;
|
|
|
|
case ICMP6_ECHO_REPLY:
|
|
return ICMP_ECHOREPLY;
|
|
|
|
case ICMP6_DST_UNREACH:
|
|
return ICMP_DEST_UNREACH;
|
|
|
|
case ICMP6_TIME_EXCEEDED:
|
|
return ICMP_TIME_EXCEEDED;
|
|
}
|
|
|
|
// We don't understand this ICMP type. Return parameter problem so the caller will bail out.
|
|
logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_type: unhandled ICMP type/code %d/%d", type, code);
|
|
return ICMP_PARAMETERPROB;
|
|
}
|
|
|
|
/* function: icmp6_to_icmp_code
|
|
* Maps ICMPv6 codes to ICMP codes. Partial implementation of RFC 6145, section 5.2.
|
|
* type - the ICMPv6 type
|
|
* code - the ICMPv6 code
|
|
*/
|
|
uint8_t icmp6_to_icmp_code(uint8_t type, uint8_t code) {
|
|
switch (type) {
|
|
case ICMP6_ECHO_REQUEST:
|
|
case ICMP6_ECHO_REPLY:
|
|
case ICMP6_TIME_EXCEEDED:
|
|
return code;
|
|
|
|
case ICMP6_DST_UNREACH:
|
|
switch (code) {
|
|
case ICMP6_DST_UNREACH_NOROUTE:
|
|
return ICMP_UNREACH_HOST;
|
|
|
|
case ICMP6_DST_UNREACH_ADMIN:
|
|
return ICMP_UNREACH_HOST_PROHIB;
|
|
|
|
case ICMP6_DST_UNREACH_BEYONDSCOPE:
|
|
return ICMP_UNREACH_HOST;
|
|
|
|
case ICMP6_DST_UNREACH_ADDR:
|
|
return ICMP_HOST_UNREACH;
|
|
|
|
case ICMP6_DST_UNREACH_NOPORT:
|
|
return ICMP_UNREACH_PORT;
|
|
|
|
// Otherwise, we don't understand this ICMPv6 type/code combination. Fall through.
|
|
}
|
|
}
|
|
|
|
logmsg_dbg(ANDROID_LOG_DEBUG, "icmp6_to_icmp_code: unhandled ICMP type/code %d/%d", type, code);
|
|
return 0;
|
|
}
|