...
 
Commits (6)
# Re2o firewall with nftables
dependencies :
This script creates a firewall from Re2o information using nftables.
# What it does :
- Fetch mac-ip table from re2o and filter traffic from the adherent NAT with it;
- Create a NAT table for FedeRez and Adherent, and NAT the admin and prerezotage VLANs properly.
# What it does not do (yet) :
- Fetch opened ports on Re2o and filter traffic with these infos.
# Install :
```
cd /usr/local/
git clone --recursive https://gitlab.rezometz.org/klafyvel/firewall.git
apt install python3 python3-click python3-iso8601
cp config.ini.example config.ini
vim config.ini
chmod +x main.py
cp firewall.service /etc/systemd/system/
systemctl start firewall.service
echo "* * * * * root /usr/bin/python3 main.py macip 2>&1 | /usr/bin/logger -t firewall" >> /etc/cron.d/firewall
```
# Usage :
See `./main.py --help`.
# Dependencies :
- re2oapi
- python3-click
......@@ -607,6 +607,12 @@ def get_ip_iterable_from_str(ip):
class NAT:
PROTOCOLS = (
'tcp',
'udp',
'icmp'
)
def __init__(self,
name,
range_in,
......@@ -648,22 +654,16 @@ class NAT:
grp: The name of the group
ports: The port range (str)
"""
CommandExec.run([
*self.nft,
"add rule ip nat {name}_nat ip saddr @{name}_nat_port_{grp} ip protocol tcp snat ip saddr map @{name}_nat_address : {ports}".format(
name=self.name,
grp=grp,
ports=ports
)
])
CommandExec.run([
*self.nft,
"add rule ip nat {name}_nat ip saddr @{name}_nat_port_{grp} ip protocol udp snat ip saddr map @{name}_nat_address : {ports}".format(
name=self.name,
grp=grp,
ports=ports
)
])
for protocol in self.PROTOCOLS:
CommandExec.run([
*self.nft,
"add rule ip nat {name}_nat ip saddr @{name}_nat_port_{grp} ip protocol {protocol} snat ip saddr map @{name}_nat_address : {ports}".format(
protocol=protocol,
name=self.name,
grp=grp,
ports=ports
)
])
def manage(self):
"""Creates the port sets, ip map and rules
......
[Unit]
Description=RezoMetz Firewall Service
Description=Re2o Firewall Service
After=network.target
[Service]
......
......@@ -19,6 +19,7 @@
Creates the nat set.
"""
import os
import logging
from configparser import ConfigParser
......@@ -26,8 +27,10 @@ from re2oapi import Re2oAPIClient
from firewall import NetfilterSet
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG = ConfigParser()
CONFIG.read('/usr/local/firewall/config.ini')
CONFIG.read(os.path.join(BASE_DIR, 'config.ini'))
api_hostname = CONFIG.get('Re2o', 'hostname')
api_password = CONFIG.get('Re2o', 'password')
......
#! /usr/bin/python3
import os
import tempfile
import logging
from logging.handlers import RotatingFileHandler
......@@ -7,6 +8,7 @@ import click
import nat as _nat
import mac_ip as _mac_ip
from firewall import CommandExec, ExecError
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
......@@ -24,25 +26,99 @@ stream_handler.setFormatter(formatter)
stream_handler.setLevel(LOG_LEVEL)
logger.addHandler(stream_handler)
def _structure(keep_nat, keep_macip):
logger.info("Loading firewall.")
if keep_nat:
logging.info("Backing up the current NAT table.")
nat_file = tempfile.NamedTemporaryFile()
try:
code, nat, *_ = CommandExec.run_check_output([
'sudo',
'/usr/sbin/nft',
'list table nat'
])
except ExecError as e:
logging.error(e)
return
else:
nat_file.write(nat.encode('utf-8'))
if keep_macip:
logging.info("Backing up the current macip set.")
macip_file = tempfile.NamedTemporaryFile()
try:
code, nat, *_ = CommandExec.run_check_output([
'sudo',
'/usr/sbin/nft',
'list set inet firewall ip_mac'
])
except ExecError as e:
logging.error(e)
return
else:
macip_file.write(nat.encode('utf-8'))
CommandExec.run([
'nft',
'-I',
BASE_DIR,
'-f',
os.path.join(BASE_DIR, 'firewall.nft')
])
if keep_macip:
logging.info("Retreiving the current macip set.")
CommandExec.run([
'nft',
'-I',
BASE_DIR,
'-f',
macip_file.name
])
macip_file.close()
else:
_mac_ip.update_macip()
if keep_nat:
logging.info("Retreiving the current NAT table.")
CommandExec.run([
'nft',
'-I',
BASE_DIR,
'-f',
nat_file.name
])
nat_file.close()
else:
_nat.main()
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
logger.info("Starting Re2o firewall manager.")
@click.option('--keep-nat/--dont-keep-nat', default=False, help='Should I keep the current NAT table ?')
@click.option('--keep-macip/--dont-keep-macip', default=False, help='Should I keep the current macip set ?')
def cli(ctx, keep_nat, keep_macip):
"""Re2o firewall manager.
Used without command, the firewall manager will load the whole firewall (i.e. the struture, the macip set and the MAC table). By default it erases the current NAT table and macp set. You can choose to keep the current values for these with the flags.
"""
if ctx.invoked_subcommand is None:
logger.info("Loading firewall.")
os.system('nft -I {install_dir} -f {firewall}'.format(
install_dir=BASE_DIR,
firewall=os.path.join(BASE_DIR, 'firewall.nft')
))
_mac_ip.update_macip()
_nat.main()
logger.info("Starting Re2o firewall manager.")
_structure(keep_nat, keep_macip)
@cli.command()
def macip():
"""Load the macip set.
Load the macip set from Re2o. This mean you need to be able to contact the Re2o server :)
"""
_mac_ip.update_macip()
@cli.command()
def nat():
"""Load the NAT table.
Generate the NAT table from the config file. You typically need to run this command only at boot.
"""
_nat.main()
if __name__ == '__main__':
......
......@@ -21,14 +21,17 @@ Creates the nat set.
import logging
import time
import os
from configparser import ConfigParser
import netaddr
from firewall import NAT
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG = ConfigParser()
CONFIG.read('/usr/local/firewall/config.ini')
CONFIG.read(os.path.join(BASE_DIR, 'config.ini'))
def create_nat_adherent():
......@@ -92,7 +95,10 @@ def main():
nat_log += aloes_nat.manage()
logging.info("Done.")
filename = "/var/log/nat-%s.log" % ctime
nat_directory = "/var/log/nat/"
if not os.path.exists(nat_directory):
os.makedirs(nat_directory)
filename = os.path.join(nat_directory, "nat_%s.log" % time.strftime('%Y_%m_%d_%Hh_%Mm'))
logging.info("Saving nat table into " + filename)
with open(filename, 'a') as f:
......
......@@ -60,7 +60,7 @@ table inet firewall {
set ldap {
type ipv4_addr
flags interval
elements = { 193.48.225.240, 193.48.225.248 }
elements = { 193.48.225.246, 193.48.225.248 }
}
set ldap_clients {
......