Generate a random IID if one is not specified.
- Add code to generate a random IPv6 address that's checksum-neutral with the NAT64 prefix and clat IPv4 address. - Only calculate the IP address after the NAT64 prefix is known. - Because the clat IPv6 address is no longer determinisitic, modify interface_poll so it checks whether the prefix has changed instead of checking whether the IPv6 address has changed. - Add/update unit tests. Change-Id: Ia53716ca5315ebdd0eaa3ad3a07552bf18e9dd5c
This commit is contained in:
parent
74151e9d0c
commit
9808952bdf
7 changed files with 270 additions and 20 deletions
|
|
@ -30,7 +30,7 @@ include $(CLEAR_VARS)
|
|||
|
||||
LOCAL_MODULE := clatd_test
|
||||
LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter
|
||||
LOCAL_SRC_FILES := clatd_test.cpp dump.c checksum.c translate.c icmp.c ipv4.c ipv6.c logging.c
|
||||
LOCAL_SRC_FILES := clatd_test.cpp checksum.c translate.c icmp.c ipv4.c ipv6.c logging.c config.c
|
||||
LOCAL_MODULE_TAGS := eng tests
|
||||
LOCAL_SHARED_LIBRARIES := liblog
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@
|
|||
#ifndef __CHECKSUM_H__
|
||||
#define __CHECKSUM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
uint32_t ip_checksum_add(uint32_t current, const void *data, int len);
|
||||
uint16_t ip_checksum_finish(uint32_t temp_sum);
|
||||
uint16_t ip_checksum(const void *data, int len);
|
||||
|
|
|
|||
8
clatd.c
8
clatd.c
|
|
@ -164,16 +164,16 @@ void interface_poll(const struct tun_data *tunnel) {
|
|||
return;
|
||||
}
|
||||
|
||||
config_generate_local_ipv6_subnet(&interface_ip->ip6);
|
||||
if(!ipv6_prefix_equal(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
|
||||
config_generate_local_ipv6_subnet(&interface_ip->ip6);
|
||||
|
||||
if(!IN6_ARE_ADDR_EQUAL(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
|
||||
char from_addr[INET6_ADDRSTRLEN], to_addr[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, from_addr, sizeof(from_addr));
|
||||
inet_ntop(AF_INET6, &interface_ip->ip6, to_addr, sizeof(to_addr));
|
||||
logmsg(ANDROID_LOG_WARN, "clat subnet changed from %s to %s", from_addr, to_addr);
|
||||
logmsg(ANDROID_LOG_WARN, "clat IPv6 address changed from %s to %s", from_addr, to_addr);
|
||||
|
||||
// Start translating packets to the new prefix.
|
||||
memcpy(&Global_Clatd_Config.ipv6_local_subnet, &interface_ip->ip6, sizeof(struct in6_addr));
|
||||
Global_Clatd_Config.ipv6_local_subnet = interface_ip->ip6;
|
||||
|
||||
// Update our packet socket filter to reflect the new 464xlat IP address.
|
||||
if (!configure_packet_socket(tunnel->read_fd6)) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# host ID to use as the source of CLAT traffic
|
||||
# this is a /128 taken out of the /64 routed to the phone
|
||||
ipv6_host_id ::464
|
||||
# Host IID to use as the source of CLAT traffic.
|
||||
# This is a /128 taken out of the /64 on the parent interface.
|
||||
# A host IID of :: means to generate a checksum-neutral, random IID.
|
||||
ipv6_host_id ::
|
||||
|
||||
# ipv4 subnet for the local traffic to use. This is a /32 host address
|
||||
ipv4_local_subnet 192.0.0.4
|
||||
|
|
|
|||
210
clatd_test.cpp
210
clatd_test.cpp
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in6.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
|
@ -370,7 +371,7 @@ void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int nu
|
|||
*reassembled_len = total_length;
|
||||
}
|
||||
|
||||
void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t len, const char *msg) {
|
||||
void check_data_matches(const void *expected, const void *actual, size_t len, const char *msg) {
|
||||
if (memcmp(expected, actual, len)) {
|
||||
// Hex dump, 20 bytes per line, one space between bytes (1 byte = 3 chars), indented by 4.
|
||||
int hexdump_len = len * 3 + (len / 20 + 1) * 5;
|
||||
|
|
@ -382,11 +383,11 @@ void check_data_matches(const uint8_t *expected, const uint8_t *actual, size_t l
|
|||
sprintf(actual_hexdump + pos, "\n ");
|
||||
pos += 4;
|
||||
}
|
||||
sprintf(expected_hexdump + pos, " %02x", expected[i]);
|
||||
sprintf(actual_hexdump + pos, " %02x", actual[i]);
|
||||
sprintf(expected_hexdump + pos, " %02x", ((uint8_t *) expected)[i]);
|
||||
sprintf(actual_hexdump + pos, " %02x", ((uint8_t *) actual)[i]);
|
||||
pos += 3;
|
||||
}
|
||||
FAIL() << msg << ": Translated packet doesn't match"
|
||||
FAIL() << msg << ": Data doesn't match"
|
||||
<< "\n Expected:" << (char *) expected_hexdump
|
||||
<< "\n Actual:" << (char *) actual_hexdump << "\n";
|
||||
}
|
||||
|
|
@ -460,6 +461,7 @@ void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *
|
|||
|
||||
translate_packet(write_fd, (version == 4), original, original_len);
|
||||
|
||||
snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg);
|
||||
if (version == 6) {
|
||||
// Translating to IPv4. Expect a tun header.
|
||||
struct tun_pi new_tun_header;
|
||||
|
|
@ -472,13 +474,15 @@ void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t *
|
|||
ASSERT_LT((size_t) len, *outlen) << msg << ": Translated packet buffer too small\n";
|
||||
EXPECT_EQ(expected_proto, new_tun_header.proto) << msg << "Unexpected tun proto\n";
|
||||
*outlen = len - sizeof(new_tun_header);
|
||||
check_packet(out, *outlen, msg);
|
||||
} else {
|
||||
FAIL() << msg << ": Packet was not translated";
|
||||
FAIL() << msg << ": Packet was not translated: len=" << len;
|
||||
*outlen = 0;
|
||||
}
|
||||
} else {
|
||||
// Translating to IPv6. Expect raw packet.
|
||||
*outlen = read(read_fd, out, *outlen);
|
||||
check_packet(out, *outlen, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,6 +518,44 @@ void check_fragment_translation(const uint8_t *original[], const size_t original
|
|||
check_packet(translated, translated_len, msg);
|
||||
}
|
||||
|
||||
int get_transport_checksum(const uint8_t *packet) {
|
||||
struct iphdr *ip;
|
||||
struct ip6_hdr *ip6;
|
||||
uint8_t protocol;
|
||||
const void *payload;
|
||||
|
||||
int version = ip_version(packet);
|
||||
switch (version) {
|
||||
case 4:
|
||||
ip = (struct iphdr *) packet;
|
||||
if (is_ipv4_fragment(ip)) {
|
||||
return -1;
|
||||
}
|
||||
protocol = ip->protocol;
|
||||
payload = ip + 1;
|
||||
break;
|
||||
case 6:
|
||||
ip6 = (struct ip6_hdr *) packet;
|
||||
protocol = ip6->ip6_nxt;
|
||||
payload = ip6 + 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (protocol) {
|
||||
case IPPROTO_UDP:
|
||||
return ((struct udphdr *) payload)->check;
|
||||
|
||||
case IPPROTO_TCP:
|
||||
return ((struct tcphdr *) payload)->check;
|
||||
|
||||
case IPPROTO_FRAGMENT:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct clat_config Global_Clatd_Config;
|
||||
|
||||
class ClatdTest : public ::testing::Test {
|
||||
|
|
@ -522,10 +564,126 @@ class ClatdTest : public ::testing::Test {
|
|||
inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet);
|
||||
inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet);
|
||||
inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet);
|
||||
Global_Clatd_Config.ipv6_host_id = in6addr_any;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ClatdTest, Sanitycheck) {
|
||||
void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) {
|
||||
if (!IN6_ARE_ADDR_EQUAL(expected, actual)) {
|
||||
char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, expected, expected_str, sizeof(expected_str));
|
||||
inet_ntop(AF_INET6, actual, actual_str, sizeof(actual_str));
|
||||
FAIL()
|
||||
<< "Unexpected IPv6 address:: "
|
||||
<< "\n Expected: " << expected_str
|
||||
<< "\n Actual: " << actual_str
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, TestIPv6PrefixEqual) {
|
||||
EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
|
||||
&Global_Clatd_Config.plat_subnet));
|
||||
EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.plat_subnet,
|
||||
&Global_Clatd_Config.ipv6_local_subnet));
|
||||
|
||||
struct in6_addr subnet2 = Global_Clatd_Config.ipv6_local_subnet;
|
||||
EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
|
||||
EXPECT_TRUE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
|
||||
|
||||
subnet2.s6_addr[6] = 0xff;
|
||||
EXPECT_FALSE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &subnet2));
|
||||
EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
|
||||
}
|
||||
|
||||
int count_onebits(const void *data, size_t size) {
|
||||
int onebits = 0;
|
||||
for (size_t pos = 0; pos < size; pos++) {
|
||||
uint8_t *byte = ((uint8_t*) data) + pos;
|
||||
for (int shift = 0; shift < 8; shift++) {
|
||||
onebits += (*byte >> shift) & 1;
|
||||
}
|
||||
}
|
||||
return onebits;
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, TestCountOnebits) {
|
||||
uint64_t i;
|
||||
i = 1;
|
||||
ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
|
||||
i <<= 61;
|
||||
ASSERT_EQ(1, count_onebits(&i, sizeof(i)));
|
||||
i |= ((uint64_t) 1 << 33);
|
||||
ASSERT_EQ(2, count_onebits(&i, sizeof(i)));
|
||||
i = 0xf1000202020000f0;
|
||||
ASSERT_EQ(5 + 1 + 1 + 1 + 4, count_onebits(&i, sizeof(i)));
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, TestGenIIDConfigured) {
|
||||
struct in6_addr myaddr, expected;
|
||||
ASSERT_TRUE(inet_pton(AF_INET6, "::bad:ace:d00d", &Global_Clatd_Config.ipv6_host_id));
|
||||
ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:0:bad:ace:d00d", &expected));
|
||||
ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &myaddr));
|
||||
config_generate_local_ipv6_subnet(&myaddr);
|
||||
expect_ipv6_addr_equal(&expected, &myaddr);
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, TestGenIIDRandom) {
|
||||
struct in6_addr interface_ipv6;
|
||||
ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &interface_ipv6));
|
||||
Global_Clatd_Config.ipv6_host_id = in6addr_any;
|
||||
|
||||
// Generate a boatload of random IIDs.
|
||||
int onebits = 0;
|
||||
uint64_t prev_iid = 0;
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
struct in6_addr myaddr = interface_ipv6;
|
||||
|
||||
config_generate_local_ipv6_subnet(&myaddr);
|
||||
|
||||
// Check the generated IP address is in the same prefix as the interface IPv6 address.
|
||||
EXPECT_TRUE(ipv6_prefix_equal(&interface_ipv6, &myaddr));
|
||||
|
||||
// Check that consecutive IIDs are not the same.
|
||||
uint64_t iid = * (uint64_t*) (&myaddr.s6_addr[8]);
|
||||
ASSERT_TRUE(iid != prev_iid)
|
||||
<< "Two consecutive random IIDs are the same: "
|
||||
<< std::showbase << std::hex
|
||||
<< iid << "\n";
|
||||
prev_iid = iid;
|
||||
|
||||
// Check that the IID is checksum-neutral with the NAT64 prefix and the
|
||||
// local prefix.
|
||||
struct in_addr *ipv4addr = &Global_Clatd_Config.ipv4_local_subnet;
|
||||
struct in6_addr *plat_subnet = &Global_Clatd_Config.plat_subnet;
|
||||
|
||||
uint16_t c1 = ip_checksum_finish(ip_checksum_add(0, ipv4addr, sizeof(*ipv4addr)));
|
||||
uint16_t c2 = ip_checksum_finish(ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
|
||||
ip_checksum_add(0, &myaddr, sizeof(myaddr)));
|
||||
|
||||
if (c1 != c2) {
|
||||
char myaddr_str[INET6_ADDRSTRLEN], plat_str[INET6_ADDRSTRLEN], ipv4_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, &myaddr, myaddr_str, sizeof(myaddr_str));
|
||||
inet_ntop(AF_INET6, plat_subnet, plat_str, sizeof(plat_str));
|
||||
inet_ntop(AF_INET, ipv4addr, ipv4_str, sizeof(ipv4_str));
|
||||
FAIL()
|
||||
<< "Bad IID: " << myaddr_str
|
||||
<< " not checksum-neutral with " << ipv4_str << " and " << plat_str
|
||||
<< std::showbase << std::hex
|
||||
<< "\n IPv4 checksum: " << c1
|
||||
<< "\n IPv6 checksum: " << c2
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// Check that IIDs are roughly random and use all the bits by counting the
|
||||
// total number of bits set to 1 in a random sample of 100000 generated IIDs.
|
||||
onebits += count_onebits(&iid, sizeof(iid));
|
||||
}
|
||||
EXPECT_LE(3190000, onebits);
|
||||
EXPECT_GE(3210000, onebits);
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, DataSanitycheck) {
|
||||
// Sanity checks the data.
|
||||
uint8_t v4_header[] = { IPV4_UDP_HEADER };
|
||||
ASSERT_EQ(sizeof(struct iphdr), sizeof(v4_header)) << "Test IPv4 header: incorrect length\n";
|
||||
|
|
@ -681,3 +839,43 @@ TEST_F(ClatdTest, Fragmentation) {
|
|||
kIPv4Fragments, kIPv4FragLengths,
|
||||
ARRAYSIZE(kIPv6Fragments), "IPv6->IPv4 fragment translation");
|
||||
}
|
||||
|
||||
void check_translate_checksum_neutral(const uint8_t *original, size_t original_len,
|
||||
size_t expected_len, const char *msg) {
|
||||
uint8_t translated[MAXMTU];
|
||||
size_t translated_len = sizeof(translated);
|
||||
do_translate_packet(original, original_len, translated, &translated_len, msg);
|
||||
EXPECT_EQ(expected_len, translated_len) << msg << ": Translated packet length incorrect\n";
|
||||
// do_translate_packet already checks packets for validity and verifies the checksum.
|
||||
int original_check = get_transport_checksum(original);
|
||||
int translated_check = get_transport_checksum(translated);
|
||||
ASSERT_NE(-1, original_check);
|
||||
ASSERT_NE(-1, translated_check);
|
||||
ASSERT_EQ(original_check, translated_check)
|
||||
<< "Not checksum neutral: original and translated checksums differ\n";
|
||||
}
|
||||
|
||||
TEST_F(ClatdTest, TranslateChecksumNeutral) {
|
||||
// Generate a random clat IPv6 address and check that translation is checksum-neutral.
|
||||
Global_Clatd_Config.ipv6_host_id = in6addr_any;
|
||||
ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54",
|
||||
&Global_Clatd_Config.ipv6_local_subnet));
|
||||
config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet);
|
||||
ASSERT_NE((uint32_t) 0x00000464, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
|
||||
ASSERT_NE((uint32_t) 0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]);
|
||||
|
||||
// Check that translating UDP packets is checksum-neutral. First, IPv4.
|
||||
uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD };
|
||||
fix_udp_checksum(udp_ipv4);
|
||||
check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
|
||||
"UDP/IPv4 -> UDP/IPv6 checksum neutral");
|
||||
|
||||
// Now try IPv6.
|
||||
uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD };
|
||||
// The test packet uses the static IID, not the random IID. Fix up the source address.
|
||||
struct ip6_hdr *ip6 = (struct ip6_hdr *) udp_ipv6;
|
||||
memcpy(&ip6->ip6_src, &Global_Clatd_Config.ipv6_local_subnet, sizeof(ip6->ip6_src));
|
||||
fix_udp_checksum(udp_ipv6);
|
||||
check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20,
|
||||
"UDP/IPv4 -> UDP/IPv6 checksum neutral");
|
||||
}
|
||||
|
|
|
|||
58
config.c
58
config.c
|
|
@ -31,6 +31,7 @@
|
|||
#include "logging.h"
|
||||
#include "getaddr.h"
|
||||
#include "clatd.h"
|
||||
#include "checksum.h"
|
||||
|
||||
struct clat_config Global_Clatd_Config;
|
||||
|
||||
|
|
@ -149,6 +150,16 @@ void free_config() {
|
|||
}
|
||||
}
|
||||
|
||||
/* function: ipv6_prefix_equal
|
||||
* compares the prefixes two ipv6 addresses. assumes the prefix lengths are both /64.
|
||||
* a1 - first address
|
||||
* a2 - second address
|
||||
* returns: 0 if the subnets are different, 1 if they are the same.
|
||||
*/
|
||||
int ipv6_prefix_equal(struct in6_addr *a1, struct in6_addr *a2) {
|
||||
return !memcmp(a1, a2, 8);
|
||||
}
|
||||
|
||||
/* function: dns64_detection
|
||||
* does dns lookups to set the plat subnet or exits on failure, waits forever for a dns response with a query backoff timer
|
||||
* net_id - (optional) netId to use, NETID_UNSET indicates use of default network
|
||||
|
|
@ -175,6 +186,28 @@ void dns64_detection(unsigned net_id) {
|
|||
}
|
||||
|
||||
|
||||
void gen_random_iid(struct in6_addr *myaddr, struct in_addr *ipv4_local_subnet,
|
||||
struct in6_addr *plat_subnet) {
|
||||
// Fill last 8 bytes of IPv6 address with random bits.
|
||||
arc4random_buf(&myaddr->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 = (myaddr->s6_addr[11] << 8) + myaddr->s6_addr[12];
|
||||
|
||||
uint32_t c1 = ip_checksum_add(0, ipv4_local_subnet, sizeof(*ipv4_local_subnet));
|
||||
uint32_t c2 = ip_checksum_add(0, plat_subnet, sizeof(*plat_subnet)) +
|
||||
ip_checksum_add(0, myaddr, sizeof(*myaddr));
|
||||
|
||||
uint16_t delta = ip_checksum_adjust(middlebytes, c1, c2);
|
||||
myaddr->s6_addr[11] = delta >> 8;
|
||||
myaddr->s6_addr[12] = delta & 0xff;
|
||||
}
|
||||
|
||||
/* function: config_generate_local_ipv6_subnet
|
||||
* generates the local ipv6 subnet when given the interface ip
|
||||
* requires config.ipv6_host_id
|
||||
|
|
@ -183,8 +216,16 @@ void dns64_detection(unsigned net_id) {
|
|||
void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip) {
|
||||
int i;
|
||||
|
||||
for(i = 2; i < 4; i++) {
|
||||
interface_ip->s6_addr32[i] = Global_Clatd_Config.ipv6_host_id.s6_addr32[i];
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_host_id)) {
|
||||
/* Generate a random interface ID. */
|
||||
gen_random_iid(interface_ip,
|
||||
&Global_Clatd_Config.ipv4_local_subnet,
|
||||
&Global_Clatd_Config.plat_subnet);
|
||||
} else {
|
||||
/* Use the specified interface ID. */
|
||||
for(i = 2; i < 4; i++) {
|
||||
interface_ip->s6_addr32[i] = Global_Clatd_Config.ipv6_host_id.s6_addr32[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,10 +236,12 @@ void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip) {
|
|||
*/
|
||||
int subnet_from_interface(cnode *root, const char *interface) {
|
||||
union anyip *interface_ip;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
|
||||
if(!config_item_ip6(root, "ipv6_host_id", "::464", &Global_Clatd_Config.ipv6_host_id))
|
||||
if(!config_item_ip6(root, "ipv6_host_id", "::", &Global_Clatd_Config.ipv6_host_id))
|
||||
return 0;
|
||||
|
||||
// TODO: check that the prefix length is /64.
|
||||
interface_ip = getinterface_ip(interface, AF_INET6);
|
||||
if(!interface_ip) {
|
||||
logmsg(ANDROID_LOG_FATAL,"unable to find an ipv6 ip on interface %s",interface);
|
||||
|
|
@ -210,6 +253,9 @@ int subnet_from_interface(cnode *root, const char *interface) {
|
|||
|
||||
config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet);
|
||||
|
||||
inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, addrstr, sizeof(addrstr));
|
||||
logmsg(ANDROID_LOG_INFO, "Using %s on %s", addrstr, interface);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -240,9 +286,6 @@ int read_config(const char *file, const char *uplink_interface, const char *plat
|
|||
|
||||
strncpy(Global_Clatd_Config.default_pdp_interface, uplink_interface, sizeof(Global_Clatd_Config.default_pdp_interface));
|
||||
|
||||
if(!subnet_from_interface(root,Global_Clatd_Config.default_pdp_interface))
|
||||
goto failed;
|
||||
|
||||
if(!config_item_int16_t(root, "mtu", "-1", &Global_Clatd_Config.mtu))
|
||||
goto failed;
|
||||
|
||||
|
|
@ -275,6 +318,9 @@ int read_config(const char *file, const char *uplink_interface, const char *plat
|
|||
}
|
||||
}
|
||||
|
||||
if(!subnet_from_interface(root,Global_Clatd_Config.default_pdp_interface))
|
||||
goto failed;
|
||||
|
||||
|
||||
return 1;
|
||||
|
||||
|
|
|
|||
1
config.h
1
config.h
|
|
@ -40,5 +40,6 @@ extern struct clat_config Global_Clatd_Config;
|
|||
int read_config(const char *file, const char *uplink_interface, const char *plat_prefix,
|
||||
unsigned net_id);
|
||||
void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip);
|
||||
int ipv6_prefix_equal(struct in6_addr *a1, struct in6_addr *a2);
|
||||
|
||||
#endif /* __CONFIG_H__ */
|
||||
|
|
|
|||
Loading…
Reference in a new issue