blob: 2a53ba80797f6034083efb7225f2df4b39cd7508 [file] [log] [blame]
// Copyright (C) 2022 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.
#include "libclat/clatutils.h"
#include <stdlib.h>
extern "C" {
#include "checksum.h"
}
namespace android {
namespace net {
namespace clat {
// Alters the bits in the IPv6 address to make them checksum neutral with v4 and nat64Prefix.
void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Prefix) {
// Fill last 8 bytes of IPv6 address with random bits.
arc4random_buf(&v6->s6_addr[8], 8);
// Make the IID checksum-neutral. That is, make it so that:
// checksum(Local IPv4 | Remote IPv4) = checksum(Local IPv6 | Remote IPv6)
// in other words (because remote IPv6 = NAT64 prefix | Remote IPv4):
// checksum(Local IPv4) = checksum(Local IPv6 | NAT64 prefix)
// Do this by adjusting the two bytes in the middle of the IID.
uint16_t middlebytes = (v6->s6_addr[11] << 8) + v6->s6_addr[12];
uint32_t c1 = ip_checksum_add(0, &v4, sizeof(v4));
uint32_t c2 = ip_checksum_add(0, &nat64Prefix, sizeof(nat64Prefix)) +
ip_checksum_add(0, v6, sizeof(*v6));
uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
v6->s6_addr[11] = delta >> 8;
v6->s6_addr[12] = delta & 0xff;
}
} // namespace clat
} // namespace net
} // namespace android