Fix postrouting rules for vpns, port forwards

This commit is contained in:
asonix 2021-05-07 11:52:58 -05:00
parent 25e8b65394
commit 750b584b8a
3 changed files with 113 additions and 47 deletions

View file

@ -158,16 +158,16 @@ pub(crate) async fn forward_postrouting(
proto: Proto, proto: Proto,
internal_ip: Ipv4Addr, internal_ip: Ipv4Addr,
internal_mask: u8, internal_mask: u8,
internal_port: u16,
external_ip: Ipv4Addr, external_ip: Ipv4Addr,
external_port: u16,
destination_ip: Ipv4Addr, destination_ip: Ipv4Addr,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
forward_postrouting_snat( forward_postrouting_snat(
proto, proto,
internal_ip, internal_ip,
internal_mask, internal_mask,
internal_port,
external_ip, external_ip,
external_port,
destination_ip, destination_ip,
|cmd| cmd.arg("-I"), |cmd| cmd.arg("-I"),
) )
@ -178,16 +178,16 @@ pub(crate) async fn delete_forward_postrouting(
proto: Proto, proto: Proto,
internal_ip: Ipv4Addr, internal_ip: Ipv4Addr,
internal_mask: u8, internal_mask: u8,
internal_port: u16,
external_ip: Ipv4Addr, external_ip: Ipv4Addr,
external_port: u16,
destination_ip: Ipv4Addr, destination_ip: Ipv4Addr,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
forward_postrouting_snat( forward_postrouting_snat(
proto, proto,
internal_ip, internal_ip,
internal_mask, internal_mask,
internal_port,
external_ip, external_ip,
external_port,
destination_ip, destination_ip,
|cmd| cmd.arg("-D"), |cmd| cmd.arg("-D"),
) )
@ -198,8 +198,8 @@ async fn forward_postrouting_snat(
proto: Proto, proto: Proto,
internal_ip: Ipv4Addr, internal_ip: Ipv4Addr,
internal_mask: u8, internal_mask: u8,
internal_port: u16,
external_ip: Ipv4Addr, external_ip: Ipv4Addr,
external_port: u16,
destination_ip: Ipv4Addr, destination_ip: Ipv4Addr,
func: impl Fn(&mut Command) -> &mut Command, func: impl Fn(&mut Command) -> &mut Command,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
@ -215,7 +215,7 @@ async fn forward_postrouting_snat(
"-m", "-m",
proto.as_iptables_str(), proto.as_iptables_str(),
"--dport", "--dport",
&external_port.to_string(), &internal_port.to_string(),
"-m", "-m",
"conntrack", "conntrack",
"--ctstate", "--ctstate",

View file

@ -109,34 +109,37 @@ pub(crate) async fn unset(interfaces: &Interfaces, rule: Rule) -> Result<(), any
dest_port, dest_port,
) )
.await?; .await?;
for iface in &interfaces.internal { for iface in interfaces.internal.iter().chain(interfaces.tunnel.iter()) {
iptables::delete_forward_postrouting( let is_nat_iface = interfaces
rule.proto,
iface.ip,
iface.mask,
interfaces.external.ip,
rule.port,
dest_ip,
)
.await?;
}
for iface in &interfaces.tunnel {
if interfaces
.nats .nats
.iter() .iter()
.any(|nat_iface| *nat_iface == iface.interface) .any(|nat_iface| *nat_iface == iface.interface);
{
let has_nat_subnet = interfaces.nats.iter().any(|nat_iface| {
*nat_iface != iface.interface
&& interfaces
.internal
.iter()
.chain(interfaces.tunnel.iter())
.any(|other_iface| {
*nat_iface == other_iface.interface
&& other_iface.ip == iface.ip
&& other_iface.mask == iface.mask
})
});
if is_nat_iface {
iptables::delete_forward_prerouting( iptables::delete_forward_prerouting(
rule.proto, iface.ip, iface.mask, rule.port, dest_ip, dest_port, rule.proto, iface.ip, iface.mask, rule.port, dest_ip, dest_port,
) )
.await?; .await?;
} else { } else if !has_nat_subnet {
iptables::delete_forward_postrouting( iptables::delete_forward_postrouting(
rule.proto, rule.proto,
iface.ip, iface.ip,
iface.mask, iface.mask,
dest_port,
interfaces.external.ip, interfaces.external.ip,
rule.port,
dest_ip, dest_ip,
) )
.await?; .await?;
@ -192,34 +195,37 @@ pub(crate) async fn apply(interfaces: &Interfaces, rule: Rule) -> Result<(), any
dest_port, dest_port,
) )
.await?; .await?;
for iface in &interfaces.internal { for iface in interfaces.internal.iter().chain(interfaces.tunnel.iter()) {
iptables::forward_postrouting( let is_nat_iface = interfaces
rule.proto,
iface.ip,
iface.mask,
interfaces.external.ip,
rule.port,
dest_ip,
)
.await?;
}
for iface in &interfaces.tunnel {
if interfaces
.nats .nats
.iter() .iter()
.any(|nat_iface| *nat_iface == iface.interface) .any(|nat_iface| *nat_iface == iface.interface);
{
let has_nat_subnet = interfaces.nats.iter().any(|nat_iface| {
*nat_iface != iface.interface
&& interfaces
.internal
.iter()
.chain(interfaces.tunnel.iter())
.any(|other_iface| {
*nat_iface == other_iface.interface
&& other_iface.ip == iface.ip
&& other_iface.mask == iface.mask
})
});
if is_nat_iface {
iptables::forward_prerouting( iptables::forward_prerouting(
rule.proto, iface.ip, iface.mask, rule.port, dest_ip, dest_port, rule.proto, iface.ip, iface.mask, rule.port, dest_ip, dest_port,
) )
.await?; .await?;
} else { } else if !has_nat_subnet {
iptables::forward_postrouting( iptables::forward_postrouting(
rule.proto, rule.proto,
iface.ip, iface.ip,
iface.mask, iface.mask,
dest_port,
interfaces.external.ip, interfaces.external.ip,
rule.port,
dest_ip, dest_ip,
) )
.await?; .await?;

View file

@ -198,6 +198,52 @@ fn filter(interfaces: &Interfaces) -> String {
// FORWARD: Forwarding traffic across interfaces // FORWARD: Forwarding traffic across interfaces
for nat_iface in &interfaces.nats {
if let Some(iface) = interfaces
.internal
.iter()
.chain(interfaces.tunnel.iter())
.find(|iface| iface.interface == *nat_iface)
{
filter += &format!(
"-A FORWARD -i {natif} -d {natip}/{natmask} -j ACCEPT\n",
natif = iface.interface,
natip = iface.ip,
natmask = iface.mask,
);
}
for iface in interfaces.internal.iter().chain(interfaces.tunnel.iter()) {
let is_nat_iface = *nat_iface == iface.interface;
let has_nat_subnet = interfaces
.internal
.iter()
.chain(interfaces.tunnel.iter())
.any(|other_iface| {
*nat_iface == other_iface.interface
&& other_iface.ip == iface.ip
&& other_iface.mask == iface.mask
});
if !is_nat_iface && !has_nat_subnet {
// Accept packets over NAT'd tunnel interfaces from pre-existing connections
filter += &format!(
"-A FORWARD -i {natif} -o {intif} -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT\n",
natif = nat_iface,
intif = iface.interface,
);
// Reject packets over NAT'd tunnel interfaces
filter += &format!(
"-A FORWARD -i {natif} -o {intif} -j REJECT --reject-with icmp-port-unreachable\n",
natif = nat_iface,
intif = iface.interface,
);
}
}
}
// Accept packets over tunnel interfaces // Accept packets over tunnel interfaces
for iface in &interfaces.tunnel { for iface in &interfaces.tunnel {
filter += &format!( filter += &format!(
@ -273,13 +319,27 @@ fn nat(interfaces: &Interfaces) -> String {
); );
for nat_iface in &interfaces.nats { for nat_iface in &interfaces.nats {
for internal in &interfaces.internal { for iface in interfaces.internal.iter().chain(interfaces.tunnel.iter()) {
nat += &format!( let is_nat_iface = *nat_iface == iface.interface;
"-A POSTROUTING -s {intip}/{intmask} -o {natiface} -j MASQUERADE\n",
intip = internal.ip, let has_nat_subnet = interfaces
intmask = internal.mask, .internal
natiface = nat_iface, .iter()
); .chain(interfaces.tunnel.iter())
.any(|other_iface| {
*nat_iface == other_iface.interface
&& other_iface.ip == iface.ip
&& other_iface.mask == iface.mask
});
if !is_nat_iface && !has_nat_subnet {
nat += &format!(
"-A POSTROUTING -s {intip}/{intmask} -o {natiface} -j MASQUERADE\n",
intip = iface.ip,
intmask = iface.mask,
natiface = nat_iface,
);
}
} }
} }