router/src/startup/preload.rs
2021-02-07 17:10:36 -06:00

276 lines
8.7 KiB
Rust

use crate::startup::Interfaces;
static UNIVERSE: &'static str = "0.0.0.0/0";
pub(crate) fn firewall_rules(interfaces: &Interfaces) -> String {
filter(interfaces) + "\n" + &nat(interfaces)
}
// FILTER table rules
fn filter(interfaces: &Interfaces) -> String {
let mut filter = String::from(
r#"*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
"#,
);
// INPUT: Incoming traffic from various interfaces
// Accept everything on loopback
filter += &format!(
"-A INPUT -i lo -s {universe} -d {universe} -j ACCEPT\n",
universe = UNIVERSE
);
// Allow internal machines to connect to anything
for iface in &interfaces.internal {
filter += &format!(
"-A INPUT -i {intif} -s {intip}/{intmask} -d {universe} -j ACCEPT\n",
intif = iface.interface,
intip = iface.ip,
intmask = iface.mask,
universe = UNIVERSE
);
}
// Disallow IP spoofing, internal IPs should only come from the internal network
// If an internal IP is seen by the external interface, it's BAD!!!!
for iface in &interfaces.internal {
filter += &format!(
"-A INPUT -i {extif} -s {intip}/{intmask} -d {universe} -j REJECT\n",
extif = interfaces.external.interface,
intip = iface.ip,
intmask = iface.mask,
universe = UNIVERSE,
);
}
// Allow ICMP traffic on external interface
filter += &format!(
"-A INPUT -i {extif} -p ICMP -s {universe} -d {extip}/{extmask} -j ACCEPT\n",
extif = interfaces.external.interface,
universe = UNIVERSE,
extip = interfaces.external.ip,
extmask = interfaces.external.mask,
);
// Don't prevent existing connections for continuing
filter += &format!(
"-A INPUT -i {extif} -s {universe} -d {extip}/{extmask} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n",
extif = interfaces.external.interface,
universe = UNIVERSE,
extip = interfaces.external.ip,
extmask = interfaces.external.mask,
);
// Allow DHCP traffic
for iface in &interfaces.internal {
filter += &format!(
"-A INPUT -i {intif} -p tcp --sport 68 --dport 67 -j ACCEPT\n",
intif = iface.interface,
);
filter += &format!(
"-A INPUT -i {intif} -p udp --sport 68 --dport 67 -j ACCEPT\n",
intif = iface.interface,
);
}
filter += &format!(
"-A INPUT -s {universe} -d {universe} -j REJECT\n",
universe = UNIVERSE
);
// OUTPUT: Outgoing traffic from vairous interfaces
// netfilter bug workaround
filter += "-A OUTPUT -m conntrack -p icmp --ctstate INVALID -j DROP\n";
// Accept everything on loopback
filter += &format!(
"-A OUTPUT -o lo -s {universe} -d {universe} -j ACCEPT\n",
universe = UNIVERSE,
);
if interfaces.shared_internal {
for iface in &interfaces.internal {
// jface (jeans iface)
for jface in &interfaces.internal {
// Allow internal traffic across all internal interfaces
filter += &format!(
"-A OUTPUT -o {intif} -s {extip}/{extmask} -d {jntip}/{jntmask} -j ACCEPT\n",
intif = iface.interface,
extip = interfaces.external.ip,
extmask = interfaces.external.mask,
jntip = jface.ip, // jeans IP
jntmask = jface.mask, // jeans mask
);
// Allow internal traffic from self to internal networks
filter += &format!(
"-A OUTPUT -o {intif} -s {intip}/32 -d {jntip}/{jntmask} -j ACCEPT\n",
intif = iface.interface,
intip = iface.ip,
jntip = jface.ip, // jeans IP
jntmask = jface.mask, // jeans mask
);
}
}
} else {
for iface in &interfaces.internal {
// Allow internal traffic only on network associated with interface
filter += &format!(
"-A OUTPUT -o {intif} -s {extip}/{extmask} -d {intip}/{intmask} -j ACCEPT\n",
intif = iface.interface,
extip = interfaces.external.ip,
extmask = interfaces.external.mask,
intip = iface.ip,
intmask = iface.mask,
);
// Allow traffic from self to networks associated with interface
filter += &format!(
"-A OUTPUT -o {intif} -s {intip}/32 -d {intip}/{intmask} -j ACCEPT\n",
intif = iface.interface,
intip = iface.ip,
intmask = iface.mask,
);
}
}
for iface in &interfaces.internal {
// Deny traffic to internal networks on external interface
filter += &format!(
"-A OUTPUT -o {extif} -s {universe} -d {intip}/{intmask} -j REJECT\n",
extif = interfaces.external.interface,
universe = UNIVERSE,
intip = iface.ip,
intmask = iface.mask,
);
}
// Allow traffic out from external interface to anywhere
filter += &format!(
"-A OUTPUT -o {extif} -s {extip}/{extmask} -d {universe} -j ACCEPT\n",
extif = interfaces.external.interface,
extip = interfaces.external.ip,
extmask = interfaces.external.mask,
universe = UNIVERSE,
);
for iface in &interfaces.internal {
// Allow DHCP traffic out from internal interfaces
filter += &format!(
"-A OUTPUT -o {intif} -p tcp -s {intip} --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT\n",
intif = iface.interface,
intip = iface.ip,
);
filter += &format!(
"-A OUTPUT -o {intif} -p udp -s {intip} --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT\n",
intif = iface.interface,
intip = iface.ip,
);
}
// Reject traffic we don't care about
filter += &format!(
"-A OUTPUT -s {universe} -d {universe} -j REJECT\n",
universe = UNIVERSE
);
// FORWARD: Forwarding traffic across interfaces
// Accept packets over tunnel interfaces
for iface in &interfaces.tunnel {
filter += &format!(
"-A FORWARD -i {tunface} -j ACCEPT\n",
tunface = iface.interface,
);
filter += &format!(
"-A FORWARD -o {tunface} -j ACCEPT\n",
tunface = iface.interface,
);
filter += &format!(
"-A OUTPUT -o {tunface} -j ACCEPT\n",
tunface = iface.interface,
);
}
// Accept TCP packets
for iface in &interfaces.internal {
filter += &format!(
"-A FORWARD -i {extif} -o {intif} -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT\n",
extif = interfaces.external.interface,
intif = iface.interface,
);
}
if interfaces.shared_internal {
for iface in &interfaces.internal {
// jface (jeans interface)
for jface in &interfaces.internal {
// Allow packets across internal interfaces
filter += &format!(
"-A FORWARD -i {intif} -o {jntif} -j ACCEPT\n",
intif = iface.interface,
jntif = jface.interface, // jntif (jeans intif)
);
}
}
} else {
for iface in &interfaces.internal {
// Allow packets across internal interface
filter += &format!(
"-A FORWARD -i {intif} -o {intif} -j ACCEPT\n",
intif = iface.interface,
);
}
}
// Forward packets to the internet
for iface in &interfaces.internal {
filter += &format!(
"-A FORWARD -i {intif} -o {extif} -j ACCEPT\n",
intif = iface.interface,
extif = interfaces.external.interface,
);
}
filter += "-A FORWARD -j REJECT\n";
filter += "COMMIT\n";
filter
}
// NAT Table rules
fn nat(interfaces: &Interfaces) -> String {
let mut nat = String::from(
r#"*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
"#,
);
nat += &format!(
"-A POSTROUTING -o {extif} -j MASQUERADE\n",
extif = interfaces.external.interface
);
nat += "COMMIT\n";
nat
}
// TODO: SSH
// # Internal interface, SSH traffic accepted on port 3128
// -A INPUT -i $INTIF -p tcp --dport 3128 -j ACCEPT
//
// # External interface, SSH traffic allowed on port 3128
// -A INPUT -i $EXTIF -m conntrack -p tcp -s $UNIVERSE -d $EXTIP --dport 3128 -j ACCEPT