Ensure CLAT-PLAT traffic is permitted in UFW

UFW is the standard local firewall framework in Debian-based
distributions. If it is installed and active, add rules that permit
routed traffic between the CLAT and the PLAT prefix. This traffic is
dropped by the default UFW ruleset, leading to issues such as #42.
This commit is contained in:
Tore Anderson
2025-02-02 20:05:07 +01:00
parent 33252dcb13
commit 92afe35b0b
3 changed files with 48 additions and 1 deletions

View File

@@ -22,6 +22,6 @@ installdeps:
# .deb/apt-get based distros # .deb/apt-get based distros
if test -x "$(APT_GET)"; then $(APT_GET) -y install perl-base perl-modules libnet-ip-perl libnet-dns-perl libio-socket-ip-perl iproute2 nftables tayga; fi if test -x "$(APT_GET)"; then $(APT_GET) -y install perl-base perl-modules libnet-ip-perl libnet-dns-perl libio-socket-ip-perl iproute2 nftables tayga; fi
# .rpm/DNF/YUM-based distros # .rpm/DNF/YUM-based distros
if test -x "$(DNF_OR_YUM)"; then $(DNF_OR_YUM) -y install perl perl-Net-IP perl-Net-DNS perl-IO-Socket-IP perl-File-Temp iproute nftables; fi if test -x "$(DNF_OR_YUM)"; then $(DNF_OR_YUM) -y install perl perl-IPC-Cmd perl-Net-IP perl-Net-DNS perl-IO-Socket-IP perl-File-Temp iproute nftables; fi
# If necessary, try to install the TAYGA .rpm using dnf/yum. It is unfortunately not available in all .rpm based distros (in particular CentOS/RHEL). # If necessary, try to install the TAYGA .rpm using dnf/yum. It is unfortunately not available in all .rpm based distros (in particular CentOS/RHEL).
if test -x "$(DNF_OR_YUM)" && test ! -x "$(TAYGA)"; then $(DNF_OR_YUM) -y install tayga || echo "ERROR: Failed to install TAYGA using dnf/yum, the package is probably not included in your distro. Try enabling the EPEL repo <URL: https://fedoraproject.org/wiki/EPEL> and try again, or install TAYGA <URL: http://www.litech.org/tayga> directly from source."; exit 1; fi if test -x "$(DNF_OR_YUM)" && test ! -x "$(TAYGA)"; then $(DNF_OR_YUM) -y install tayga || echo "ERROR: Failed to install TAYGA using dnf/yum, the package is probably not included in your distro. Try enabling the EPEL repo <URL: https://fedoraproject.org/wiki/EPEL> and try again, or install TAYGA <URL: http://www.litech.org/tayga> directly from source."; exit 1; fi

View File

@@ -262,6 +262,18 @@ L<https://nftables.org/projects/nftables/>. Required if I<ctmark> is set.
Path to the B<tayga> binary from the TAYGA package available at Path to the B<tayga> binary from the TAYGA package available at
L<http://www.litech.org/tayga>. Required. L<http://www.litech.org/tayga>. Required.
=item B<cmd-ufw=path> (default: assume in $PATH)
Path to the B<ufw> binary from the UFW local firewall framework available at
L<https://launchpad.net/ufw> commonly seen on Debian-based distributions. If
this command is present on the system, and B<ufw status> reports that the
firewall is active, B<clatd> will add firewall rules ensuring traffic between
the CLAT and the PLAT prefix is allowed when it is starting up, and remove them
when it is shutting down.
If you don't want B<clatd> to add and remove UFW firewall rules, set this to an
empty string.
=item B<forwarding-enable=bool> (default: I<yes>) =item B<forwarding-enable=bool> (default: I<yes>)
Controls whether or not B<clatd> should enable IPv6 forwarding if necessary. Controls whether or not B<clatd> should enable IPv6 forwarding if necessary.

35
clatd
View File

@@ -24,6 +24,7 @@
# clatd(8) for more information. # clatd(8) for more information.
# #
use strict; use strict;
use IPC::Cmd qw(can_run);
use Net::IP; use Net::IP;
my $VERSION = "1.6nat46"; my $VERSION = "1.6nat46";
@@ -43,6 +44,7 @@ $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{"cmd-ufw"} = "ufw"; # assume in $PATH
$CFG{"ctmark"} = undef; # 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
@@ -604,6 +606,7 @@ my $cleanup_zero_proxynd_sysctl; # zero proxy_ndp sysctl if set
my $cleanup_remove_proxynd_entry, # true if having added proxynd entry my $cleanup_remove_proxynd_entry, # true if having added proxynd entry
my $cleanup_remove_nftable; # true if having added an nftable my $cleanup_remove_nftable; # true if having added an nftable
my $cleanup_remove_clat_iprule; # true if having added clat iprule my $cleanup_remove_clat_iprule; # true if having added clat iprule
my $cleanup_remove_ufw_rules; # true if having added ufw rules
my $cleanup_restore_local_iprule_prio; # true if having reordered local iprule my $cleanup_restore_local_iprule_prio; # true if having reordered local iprule
my @cleanup_restore_v4_defaultroutes; # temporarily replaced defaultroutes my @cleanup_restore_v4_defaultroutes; # temporarily replaced defaultroutes
@@ -662,6 +665,14 @@ sub cleanup_and_exit {
d("Cleanup: Removing ip rule for redirecting inbound traffic to CLAT"); d("Cleanup: Removing ip rule for redirecting inbound traffic to CLAT");
cmd(\&w, cfg("cmd-ip"), qw(-6 rule del prio 0 table), cfg("route-table")); cmd(\&w, cfg("cmd-ip"), qw(-6 rule del prio 0 table), cfg("route-table"));
} }
if(defined($cleanup_remove_ufw_rules)) {
cmd(\&w, cfg("cmd-ufw"), qw(route delete allow in on), cfg("clat-dev"),
"from", cfg("clat-v6-addr"), qw(out on), cfg("plat-dev"), "to",
cfg("plat-prefix"));
cmd(\&w, cfg("cmd-ufw"), qw(route delete allow in on), cfg("plat-dev"),
"from", cfg("plat-prefix"), qw(out on), cfg("clat-dev"), "to",
cfg("clat-v6-addr"));
}
exit($exitcode); exit($exitcode);
} }
@@ -885,6 +896,30 @@ if(cfgbool("forwarding-enable")) {
} }
} }
#
# Add firewall rules to allow PLAT-CLAT traffic if a supported local firewall
# framework is present and active
#
if(can_run(cfg("cmd-ufw"))) {
open(my $fd, '-|', cfg("cmd-ufw"), "status")
or err("'ufw status' failed to execute");
while(<$fd>) {
if(/^Status: active$/) {
p("UFW local firewall framework active, allowing CLAT-PLAT traffic");
cmd(\&err, cfg("cmd-ufw"), qw(route allow in on), cfg("clat-dev"),
"from", cfg("clat-v6-addr"), qw(out on), cfg("plat-dev"), "to",
cfg("plat-prefix"));
cmd(\&err, cfg("cmd-ufw"), qw(route allow in on), cfg("plat-dev"),
"from", cfg("plat-prefix"), qw(out on), cfg("clat-dev"), "to",
cfg("clat-v6-addr"));
$cleanup_remove_ufw_rules = 1;
}
}
close($fd) or err("'ufw status' failed");
} else {
d("UFW command '", cfg("cmd-ufw"), "' not found, not installing UFW rules");
}
# #
# Enable ND proxy for the CLAT's IPv6 address on the interface facing the PLAT # Enable ND proxy for the CLAT's IPv6 address on the interface facing the PLAT
# #