Fix postrouting rules for vpns, port forwards
This commit is contained in:
parent
25e8b65394
commit
750b584b8a
3 changed files with 113 additions and 47 deletions
|
@ -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",
|
||||||
|
|
74
src/rules.rs
74
src/rules.rs
|
@ -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?;
|
||||||
|
|
|
@ -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,15 +319,29 @@ 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()) {
|
||||||
|
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 {
|
||||||
nat += &format!(
|
nat += &format!(
|
||||||
"-A POSTROUTING -s {intip}/{intmask} -o {natiface} -j MASQUERADE\n",
|
"-A POSTROUTING -s {intip}/{intmask} -o {natiface} -j MASQUERADE\n",
|
||||||
intip = internal.ip,
|
intip = iface.ip,
|
||||||
intmask = internal.mask,
|
intmask = iface.mask,
|
||||||
natiface = nat_iface,
|
natiface = nat_iface,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nat += "COMMIT\n";
|
nat += "COMMIT\n";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue