Share IPv6 address with host OS by default
Adds support for clat-v6-addr=shared and make this the default behaviour. This makes the CLAT function share the address the host OS uses for direct IPv6 connection towards the PLAT prefix, thus removing the previous requirement for a secondary IPv6 address dedicated to the CLAT function. When using a shared address in this manner, enable connection tracking marking by default (so that direct IPv6 connections from the host OS to IPv4 destinations behind the PLAT keeps working) and disable Proxy-ND (as there is no need for it, as the host OS kernel will handle NDP interactions all on its own). To use the previous default behaviour, use clat-v6-addr=derived. Closes #25 Closes #46
This commit is contained in:
76
README.pod
76
README.pod
@@ -193,32 +193,41 @@ functional references to it in application-level payload, and so on.
|
|||||||
|
|
||||||
The default address is one from I<RFC 7335>.
|
The default address is one from I<RFC 7335>.
|
||||||
|
|
||||||
=item B<clat-v6-addr=ipv6-address> (default: auto-generated)
|
=item B<clat-v6-addr=[ipv6-address|shared|derived> (default: I<shared>)
|
||||||
|
|
||||||
The IPv6 address of the CLAT. Traffic to/from the B<clat-v4-addr> will be
|
The IPv6 address of the CLAT. Traffic to/from the B<clat-v4-addr> will be
|
||||||
translated into this address. When using B<clatd> as an SIIT-DC Edge Relay, you
|
translated into this address. When using B<clatd> as an SIIT-DC Edge Relay, you
|
||||||
will want to set this to the same IPv6 address in the Explicit Address Mapping
|
will want to set this to the same IPv6 address in the Explicit Address Mapping
|
||||||
configured in the SIIT-DC Border Relay.
|
configured in the SIIT-DC Border Relay.
|
||||||
|
|
||||||
By default, B<clatd> will attempt to figure out which network device will be
|
When set to I<shared> (the default), B<clatd> will re-use and share the primary
|
||||||
used for traffic towards the PLAT, see if there is any SLAAC-based globally
|
IPv6 address used by the host OS when communicating with directly with the PLAT
|
||||||
scoped addresses on it (i.e., a /64 with '0xfffe' in the middle of the
|
prefix. This allows B<clatd> to operate without requiring a separate, dedicated
|
||||||
Interface ID), and will if so substitute that '0xfffe' value with '0xc1a7'
|
IPv6 address assigned to the CLAT function. While this mode is the most
|
||||||
("clat") to generate a CLAT IPv6 address.
|
compatible with various network deployments, it comes with certain trade-offs,
|
||||||
|
see the B<LIMITATIONS> section for more information.
|
||||||
|
|
||||||
If only a non-SLAAC global address is found on the PLAT-facing device,
|
When set to I<derived>, B<clatd> will attempt to figure out which network
|
||||||
B<clatd> will substitute its Interface ID with a random integer and use the
|
device will be used for traffic towards the PLAT, see if there is any
|
||||||
result as the CLAT IPv6 address. It will only do so if the prefix length is
|
SLAAC-based globally scoped addresses on it (i.e., a /64 with '0xfffe' in the
|
||||||
/120 or smaller, as otherwise the risk of IID collisions is considered to be
|
middle of the Interface ID), and will if so substitute that '0xfffe' value with
|
||||||
too high. Note that on most Perl platforms, the I<rand()> function is limited
|
'0xc1a7' ("clat") to generate a CLAT IPv6 address.
|
||||||
to 48 bits, which means that for longer IIDs, the least significant bits will
|
|
||||||
be all 0.
|
If only a non-SLAAC global address is found on the PLAT-facing device, B<clatd>
|
||||||
|
will substitute its Interface ID with a random integer and use the result as
|
||||||
|
the CLAT IPv6 address. It will only do so if the prefix length is /120 or
|
||||||
|
smaller, as otherwise the risk of IID collisions is considered to be too high.
|
||||||
|
Note that on most Perl platforms, the I<rand()> function is limited to 48 bits,
|
||||||
|
which means that for longer IIDs, the least significant bits will be all 0.
|
||||||
|
|
||||||
|
The I<derived> mode is not guaranteed to result in a working configuration, see
|
||||||
|
the B<LIMITATIONS> section for more information.
|
||||||
|
|
||||||
If multiple addresses are found in either category, the one that shares the
|
If multiple addresses are found in either category, the one that shares the
|
||||||
longest common prefix with the PLAT prefix will be preferred when deriving
|
longest common prefix with the PLAT prefix will be preferred when deriving
|
||||||
the CLAT IPv6 address according to the algorithm described above.
|
the CLAT IPv6 address according to the algorithm described above.
|
||||||
|
|
||||||
=item B<ctmark> (default: 0)
|
=item B<ctmark> (default: I<0xc1a7> if I<clat-v6-addr=shared>, otherwise I<0>)
|
||||||
|
|
||||||
If set to a non-zero integer, nftables will be used to mark outgoing
|
If set to a non-zero integer, nftables will be used to mark outgoing
|
||||||
connections through the CLAT with this connection tracking mark, and the Linux
|
connections through the CLAT with this connection tracking mark, and the Linux
|
||||||
@@ -282,7 +291,7 @@ DNS64 answers using the method in I<RFC 7050>.
|
|||||||
The IPv6 translation prefix fallback. This is used if no plat-prefix is set
|
The IPv6 translation prefix fallback. This is used if no plat-prefix is set
|
||||||
or auto detected.
|
or auto detected.
|
||||||
|
|
||||||
=item B<proxynd-enable> (default: I<yes>)
|
=item B<proxynd-enable> (default: I<no> if I<clat-v6-addr=shared>, otherwise I<yes>)
|
||||||
|
|
||||||
Controls whether or not B<clatd> should add a Proxy-ND entry for the CLAT IPv6
|
Controls whether or not B<clatd> should add a Proxy-ND entry for the CLAT IPv6
|
||||||
address on the network device facing the PLAT. This is probably necessary
|
address on the network device facing the PLAT. This is probably necessary
|
||||||
@@ -292,6 +301,10 @@ point-to-point links like PPP or 3GPP mobile broadband, as in those cases
|
|||||||
IPv6 ND isn't used. However it doesn't hurt to add Proxy-ND entries in that
|
IPv6 ND isn't used. However it doesn't hurt to add Proxy-ND entries in that
|
||||||
case, either.
|
case, either.
|
||||||
|
|
||||||
|
If the CLAT is sharing an IPv6 address with the host OS, this is not necessary
|
||||||
|
as the host OS will be handling NDP anyway, so Proxy-ND does get enabled by
|
||||||
|
default when I<clat-v6-addr> is set to its default value I<shared>.
|
||||||
|
|
||||||
Any entries added wil be removed when B<clatd> is shutting down.
|
Any entries added wil be removed when B<clatd> is shutting down.
|
||||||
|
|
||||||
=item B<route-table> (default: I<0xc1a7>)
|
=item B<route-table> (default: I<0xc1a7>)
|
||||||
@@ -406,15 +419,25 @@ unset or 0, there is no default.
|
|||||||
|
|
||||||
=head1 LIMITATIONS
|
=head1 LIMITATIONS
|
||||||
|
|
||||||
If no IPv6 addresses on the PLAT-facing device are EUI-64-derived (e.g., when
|
When using B<clat-v6-addr=shared> (or when B<clat-v6-addr> is set to another
|
||||||
using SLAAC with I<RFC 4941> or I<RFC 7217> privacy addressing or static
|
address assigned to a local interface) and B<ctmark> is set to 0, the host OS
|
||||||
addresses), B<clatd> will generate and use an CLAT IPv6 address using a random
|
will not be able to communicate bi-directionally with IPv4 destinations
|
||||||
Interface ID from the same subnet prefix (if it is /120 or shorter).
|
directly through the PLAT (e.g., I<ping6 64:ff9b::192.0.2.1>). This is because
|
||||||
I<RFC 6877> suggests DHCPv6 IA_PD should be attempted in this case instead, but
|
the response traffic will be routed back to the CLAT, and ultimately return to
|
||||||
this isn't currently implemented.
|
the Linux kernel as an IPv4 packet, which does not match the outgoing IPv6
|
||||||
|
socket. Such direct communication is normal when using DNS64 synthesis for all
|
||||||
|
queries (as opposed to just I<ipv4only.arpa>).
|
||||||
|
|
||||||
|
When using B<clat-v6-addr=derived> and no IPv6 addresses on the PLAT-facing
|
||||||
|
device are EUI-64-derived (e.g., when using SLAAC with I<RFC 4941> or I<RFC
|
||||||
|
7217> privacy addressing or static addresses), B<clatd> will generate and use
|
||||||
|
an CLAT IPv6 address using a random Interface ID from the same subnet prefix
|
||||||
|
(if it is /120 or shorter). I<RFC 6877> suggests DHCPv6 IA_PD should be
|
||||||
|
attempted in this case instead, but this isn't currently implemented.
|
||||||
|
|
||||||
B<clatd> will not attempt to perform Duplicate Address Detection for the IPv6
|
B<clatd> will not attempt to perform Duplicate Address Detection for the IPv6
|
||||||
address it generates. This is a violation of I<RFC 6877>.
|
address it generates when using B<clat-v6-addr=derived>. This is a violation of
|
||||||
|
I<RFC 6877>.
|
||||||
|
|
||||||
There is no guarantee that the generated CLAT IPv6 address is in fact usable,
|
There is no guarantee that the generated CLAT IPv6 address is in fact usable,
|
||||||
as the network might block its use.
|
as the network might block its use.
|
||||||
@@ -423,15 +446,6 @@ If the upstream network is using DHCPv6, B<clatd> will not be able to generate
|
|||||||
a CLAT IPv6 address at all, due to the fact that DHCPv6-assigned addresses do
|
a CLAT IPv6 address at all, due to the fact that DHCPv6-assigned addresses do
|
||||||
not carry a prefix length.
|
not carry a prefix length.
|
||||||
|
|
||||||
If B<clat-v6-addr> is set to an address assigned to a local interface and
|
|
||||||
B<ctmark> is not set, the host OS will not be able to communicate
|
|
||||||
bi-directionally with IPv4 destinations directly through the PLAT (e.g.,
|
|
||||||
I<ping6 64:ff9b::192.0.2.1>). This is because the response traffic will be
|
|
||||||
routed back to the CLAT, and ultimately return to the Linux kernel as an IPv4
|
|
||||||
packet, which does not match the outgoing IPv6 socket. Such direct
|
|
||||||
communication is normal when using DNS64 synthesis for all queries (as opposed
|
|
||||||
to just I<ipv4only.arpa>).
|
|
||||||
|
|
||||||
B<clatd> will not attempt to perform a connectivity check to a discovered PLAT
|
B<clatd> will not attempt to perform a connectivity check to a discovered PLAT
|
||||||
prefix before setting up the CLAT, as I<RFC 7050> suggest it should.
|
prefix before setting up the CLAT, as I<RFC 7050> suggest it should.
|
||||||
|
|
||||||
|
|||||||
42
clatd
42
clatd
@@ -38,17 +38,17 @@ $CFG{"script-up"} = undef; # sh script to run when starting up
|
|||||||
$CFG{"script-down"} = undef; # sh script to run when shutting down
|
$CFG{"script-down"} = undef; # sh script to run when shutting down
|
||||||
$CFG{"clat-dev"} = "clat"; # TUN interface name to use
|
$CFG{"clat-dev"} = "clat"; # TUN interface name to use
|
||||||
$CFG{"clat-v4-addr"} = "192.0.0.1"; # from RFC 7335
|
$CFG{"clat-v4-addr"} = "192.0.0.1"; # from RFC 7335
|
||||||
$CFG{"clat-v6-addr"} = undef; # derive from existing SLAAC addr
|
$CFG{"clat-v6-addr"} = "shared"; # re-use primary address from host OS
|
||||||
$CFG{"dns64-servers"} = undef; # use system resolver by default
|
$CFG{"dns64-servers"} = undef; # use system resolver by default
|
||||||
$CFG{"cmd-ip"} = "ip"; # assume in $PATH
|
$CFG{"cmd-ip"} = "ip"; # assume in $PATH
|
||||||
$CFG{"cmd-nft"} = "nft"; # assume in $PATH
|
$CFG{"cmd-nft"} = "nft"; # assume in $PATH
|
||||||
$CFG{"cmd-tayga"} = "tayga"; # assume in $PATH
|
$CFG{"cmd-tayga"} = "tayga"; # assume in $PATH
|
||||||
$CFG{"ctmark"} = 0; # match ctmark for routing pkts to CLAT
|
$CFG{"ctmark"} = undef; # match ctmark for routing pkts to CLAT
|
||||||
$CFG{"forwarding-enable"} = 1; # enable ipv6 forwarding?
|
$CFG{"forwarding-enable"} = 1; # enable ipv6 forwarding?
|
||||||
$CFG{"plat-dev"} = undef; # PLAT-facing device, default detect
|
$CFG{"plat-dev"} = undef; # PLAT-facing device, default detect
|
||||||
$CFG{"plat-prefix"} = undef; # detect using DNS64 by default
|
$CFG{"plat-prefix"} = undef; # detect using DNS64 by default
|
||||||
$CFG{"plat-fallback-prefix"} = undef; # fallback prefix if no prefix is found
|
$CFG{"plat-fallback-prefix"} = undef; # fallback prefix if no prefix is found
|
||||||
$CFG{"proxynd-enable"} = 1; # add proxy-nd entry for clat?
|
$CFG{"proxynd-enable"} = undef; # add proxy-nd entry for clat?
|
||||||
$CFG{"route-table"} = 0xc1a7; # add route to CLAT in this table
|
$CFG{"route-table"} = 0xc1a7; # add route to CLAT in this table
|
||||||
$CFG{"tayga-conffile"} = undef; # make a temporary one by default
|
$CFG{"tayga-conffile"} = undef; # make a temporary one by default
|
||||||
$CFG{"tayga-v4-addr"} = "192.0.0.2"; # from RFC 7335
|
$CFG{"tayga-v4-addr"} = "192.0.0.2"; # from RFC 7335
|
||||||
@@ -394,6 +394,7 @@ sub get_plat_prefix {
|
|||||||
sub get_plat_dev {
|
sub get_plat_dev {
|
||||||
d("get_plat_dev(): finding which network dev faces the PLAT");
|
d("get_plat_dev(): finding which network dev faces the PLAT");
|
||||||
my $plat_dev;
|
my $plat_dev;
|
||||||
|
my $plat_dev_srcip;
|
||||||
my $plat_prefix = cfg("plat-prefix");
|
my $plat_prefix = cfg("plat-prefix");
|
||||||
if(!$plat_prefix) {
|
if(!$plat_prefix) {
|
||||||
err("get_plat_dev(): No PLAT prefix to work with");
|
err("get_plat_dev(): No PLAT prefix to work with");
|
||||||
@@ -406,9 +407,13 @@ sub get_plat_dev {
|
|||||||
d("get_plat_dev(): Found PLAT-facing device: $1");
|
d("get_plat_dev(): Found PLAT-facing device: $1");
|
||||||
$plat_dev = $1;
|
$plat_dev = $1;
|
||||||
}
|
}
|
||||||
|
if(/ src (\S+) /) {
|
||||||
|
d("get_plat_dev(): Found PLAT-facing device source IP: $1");
|
||||||
|
$plat_dev_srcip = $1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
close($fd) or err("get_plat_dev(): 'ip -6 route get $plat_prefix' failed");
|
close($fd) or err("get_plat_dev(): 'ip -6 route get $plat_prefix' failed");
|
||||||
return $plat_dev;
|
return ($plat_dev, $plat_dev_srcip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -766,9 +771,34 @@ if(!$CFG{"plat-prefix"}) {
|
|||||||
}
|
}
|
||||||
p("Using PLAT (NAT64) prefix: $CFG{'plat-prefix'}");
|
p("Using PLAT (NAT64) prefix: $CFG{'plat-prefix'}");
|
||||||
}
|
}
|
||||||
$CFG{"plat-dev"} ||= get_plat_dev();
|
my @plat_dev = get_plat_dev();
|
||||||
|
$CFG{"plat-dev"} ||= $plat_dev[0];
|
||||||
p("Device facing the PLAT: ", $CFG{"plat-dev"});
|
p("Device facing the PLAT: ", $CFG{"plat-dev"});
|
||||||
$CFG{"clat-v6-addr"} ||= get_clat_v6_addr();
|
|
||||||
|
if($CFG{"clat-v6-addr"} eq "shared") {
|
||||||
|
if(!$plat_dev[1]) {
|
||||||
|
err("Could not determine source IP facing the PLAT, needed due to using ",
|
||||||
|
"clat-v6-addr=shared");
|
||||||
|
}
|
||||||
|
$CFG{"clat-v6-addr"} = $plat_dev[1];
|
||||||
|
if(!defined($CFG{"proxynd-enable"})) {
|
||||||
|
$CFG{"proxynd-enable"} = 0;
|
||||||
|
}
|
||||||
|
if(!defined($CFG{"ctmark"})) {
|
||||||
|
$CFG{"ctmark"} = 0xc1a7;
|
||||||
|
}
|
||||||
|
} elsif($CFG{"clat-v6-addr"} eq "derived") {
|
||||||
|
$CFG{"clat-v6-addr"} = get_clat_v6_addr();
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fill defaults for proxynd-enable and ctmark for clat-v6-addr!=shared
|
||||||
|
if(!defined($CFG{"proxynd-enable"})) {
|
||||||
|
$CFG{"proxynd-enable"} = 1;
|
||||||
|
}
|
||||||
|
if(!defined($CFG{"ctmark"})) {
|
||||||
|
$CFG{"ctmark"} = 0;
|
||||||
|
}
|
||||||
|
|
||||||
p("Using CLAT IPv4 address: ", $CFG{"clat-v4-addr"});
|
p("Using CLAT IPv4 address: ", $CFG{"clat-v4-addr"});
|
||||||
p("Using CLAT IPv6 address: ", $CFG{"clat-v6-addr"});
|
p("Using CLAT IPv6 address: ", $CFG{"clat-v6-addr"});
|
||||||
if(!$CFG{"v4-defaultroute-advmss"} and cfgint("v4-defaultroute-mtu")) {
|
if(!$CFG{"v4-defaultroute-advmss"} and cfgint("v4-defaultroute-mtu")) {
|
||||||
|
|||||||
Reference in New Issue
Block a user