summaryrefslogtreecommitdiffstats
path: root/ipv6.c
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2013-04-10 12:24:56 +0900
committerLorenzo Colitti <lorenzo@google.com>2013-04-12 13:42:58 +0900
commitcd70b354eb985678175904a937085bed6094af77 (patch)
tree0a3664daec00a5a608f851a4f8e767cd5c072d3d /ipv6.c
parentee80ca65907d214e2483e315a1ba7f610184de03 (diff)
downloadandroid_external_android-clat-cd70b354eb985678175904a937085bed6094af77.tar.gz
android_external_android-clat-cd70b354eb985678175904a937085bed6094af77.tar.bz2
android_external_android-clat-cd70b354eb985678175904a937085bed6094af77.zip
Support translating ICMP errors.
When receiving ICMPv6 messages from IPv6-only nodes, use 255.0.0.<ttl> as a fake IPv4 source address. It's better than nothing. Bug: 8276725 Change-Id: Iae93f75764cb9cd875af9bb5f1862a0dce2c2fa7
Diffstat (limited to 'ipv6.c')
-rw-r--r--ipv6.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/ipv6.c b/ipv6.c
index bb1dc24..ef1e62f 100644
--- a/ipv6.c
+++ b/ipv6.c
@@ -64,12 +64,14 @@ int icmp6_packet(clat_packet out, int pos, const struct icmp6_hdr *icmp6, uint32
* fmt - printf-style format, use %s to place the address
* badaddr - the bad address in question
*/
-void log_bad_address(const char *fmt, const struct in6_addr *badaddr) {
+void log_bad_address(const char *fmt, const struct in6_addr *src, const struct in6_addr *dst) {
#if CLAT_DEBUG
- char badaddr_str[INET6_ADDRSTRLEN];
+ char srcstr[INET6_ADDRSTRLEN];
+ char dststr[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, badaddr, badaddr_str, sizeof(badaddr_str));
- logmsg_dbg(ANDROID_LOG_ERROR,fmt,badaddr_str);
+ inet_ntop(AF_INET6, src, srcstr, sizeof(srcstr));
+ inet_ntop(AF_INET6, dst, dststr, sizeof(dststr));
+ logmsg_dbg(ANDROID_LOG_ERROR, fmt, srcstr, dststr);
#endif
}
@@ -91,22 +93,27 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) {
int i;
if(len < sizeof(struct ip6_hdr)) {
- logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header");
+ logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for an ip6 header: %d", len);
return 0;
}
if(IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
- log_bad_address("ipv6_packet/multicast %s", &ip6->ip6_dst);
+ log_bad_address("ipv6_packet/multicast %s->%s", &ip6->ip6_src, &ip6->ip6_dst);
return 0; // silently ignore
}
- if (!is_in_plat_subnet(&ip6->ip6_src) && ip6->ip6_nxt) {
- log_bad_address("ipv6_packet/wrong source address: %s", &ip6->ip6_src);
- return 0;
- }
-
- if(!IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) {
- log_bad_address("ipv6_packet/wrong destination address: %s", &ip6->ip6_dst);
+ // If the packet is not from the plat subnet to the local subnet, or vice versa, drop it, unless
+ // it's an ICMP packet (which can come from anywhere). We do not send IPv6 packets from the plat
+ // subnet to the local subnet, but these can appear as inner packets in ICMP errors, so we need
+ // to translate them. We accept third-party ICMPv6 errors, even though their source addresses
+ // cannot be translated, so that things like unreachables and traceroute will work. fill_ip_header
+ // takes care of faking a source address for them.
+ if (!(is_in_plat_subnet(&ip6->ip6_src) &&
+ IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) &&
+ !(is_in_plat_subnet(&ip6->ip6_dst) &&
+ IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet)) &&
+ ip6->ip6_nxt != IPPROTO_ICMPV6) {
+ log_bad_address("ipv6_packet/wrong source address: %s->%s", &ip6->ip6_src, &ip6->ip6_dst);
return 0;
}
@@ -141,7 +148,7 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) {
len_left);
} else {
#if CLAT_DEBUG
- logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x",ip6->ip6_nxt);
+ logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt);
logcat_hexdump("ipv6/nxthdr", packet, len);
#endif
return 0;