Remplissage de la table NAT.
This commit is contained in:
parent
f5c9eeda5a
commit
f160b51e33
4 changed files with 375 additions and 13 deletions
144
.gitignore
vendored
Normal file
144
.gitignore
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
Pipfile*
|
||||||
|
# Created by https://www.gitignore.io/api/vim,python
|
||||||
|
# Edit at https://www.gitignore.io/?templates=vim,python
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
### Python Patch ###
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
*~
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/vim,python
|
|
@ -73,10 +73,4 @@ table inet firewall {
|
||||||
}
|
}
|
||||||
|
|
||||||
table nat {
|
table nat {
|
||||||
# TODO : on met 27 Ips internes par ip publiques
|
|
||||||
# Users : 193.48.225.10-119
|
|
||||||
# Prerezotage 193.48.225.240-254
|
|
||||||
# Aloes : 193.48.225.120-129
|
|
||||||
# Federez : 193.48.225.130-199
|
|
||||||
# Server : 193.48.225.200-209
|
|
||||||
}
|
}
|
||||||
|
|
46
firewall.py
46
firewall.py
|
@ -89,12 +89,35 @@ class Parser:
|
||||||
return netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded)
|
return netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded)
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def IPv4(ip):
|
def IPv4(ip):
|
||||||
"""Check an IPv4 validity."""
|
"""Check an IPv4 validity.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ip: can either be a tuple (in this case returns an IPRange), a
|
||||||
|
single IP address or a IP Network.
|
||||||
|
"""
|
||||||
|
if isinstance(ip, tuple):
|
||||||
|
begin, end = ip
|
||||||
|
return netaddr.IPRange(begin, end, version=4)
|
||||||
|
try:
|
||||||
return netaddr.IPAddress(ip, version=4)
|
return netaddr.IPAddress(ip, version=4)
|
||||||
|
except ValueError:
|
||||||
|
return netaddr.IPNetwork(ip, version=4)
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def IPv6(ip):
|
def IPv6(ip):
|
||||||
"""Check a IPv6 validity."""
|
"""Check a IPv6 validity.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ip: can either be a tuple (in this case returns an IPRange), a
|
||||||
|
single IP address or a IP Network.
|
||||||
|
"""
|
||||||
|
if isinstance(ip, tuple):
|
||||||
|
begin, end = ip
|
||||||
|
return netaddr.IPRange(begin, end, version=6)
|
||||||
|
try:
|
||||||
return netaddr.IPAddress(ip, version=6)
|
return netaddr.IPAddress(ip, version=6)
|
||||||
|
except ValueError:
|
||||||
|
return netaddr.IPNetwork(ip, version=6)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def protocol(protocol):
|
def protocol(protocol):
|
||||||
"""Check a protocol validity."""
|
"""Check a protocol validity."""
|
||||||
|
@ -120,13 +143,17 @@ class NetfilterSet:
|
||||||
|
|
||||||
ADDRESS_FAMILIES = {'ip', 'ip6', 'inet', 'arp', 'bridge', 'netdev'}
|
ADDRESS_FAMILIES = {'ip', 'ip6', 'inet', 'arp', 'bridge', 'netdev'}
|
||||||
|
|
||||||
|
FLAGS = {'constant', 'interval', 'timeout'}
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name,
|
name,
|
||||||
type_, # e.g.: ('MAC', 'IPv4')
|
type_, # e.g.: ('MAC', 'IPv4')
|
||||||
target_content=None,
|
target_content=None,
|
||||||
use_sudo=True,
|
use_sudo=True,
|
||||||
address_family='inet', # Manage both IPv4 and IPv6.
|
address_family='inet', # Manage both IPv4 and IPv6.
|
||||||
table_name='filter'):
|
table_name='filter',
|
||||||
|
flags = []
|
||||||
|
):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.content = set()
|
self.content = set()
|
||||||
# self.type
|
# self.type
|
||||||
|
@ -135,6 +162,7 @@ class NetfilterSet:
|
||||||
# self.address_family
|
# self.address_family
|
||||||
self.set_address_family(address_family)
|
self.set_address_family(address_family)
|
||||||
self.table = table_name
|
self.table = table_name
|
||||||
|
self.set_flags(flags)
|
||||||
sudo = ["/usr/bin/sudo"] * int(bool(use_sudo))
|
sudo = ["/usr/bin/sudo"] * int(bool(use_sudo))
|
||||||
self.nft = [*sudo, "/usr/sbin/nft"]
|
self.nft = [*sudo, "/usr/sbin/nft"]
|
||||||
if target_content:
|
if target_content:
|
||||||
|
@ -167,6 +195,13 @@ class NetfilterSet:
|
||||||
'Invalid address_family: "{}".'.format(address_family))
|
'Invalid address_family: "{}".'.format(address_family))
|
||||||
self.address_family = address_family
|
self.address_family = address_family
|
||||||
|
|
||||||
|
def set_flags(self, flags_):
|
||||||
|
"""Check set flags validity before saving them."""
|
||||||
|
for f in flags_:
|
||||||
|
if f not in self.FLAGS:
|
||||||
|
raise ValueError('Invalid flag: "{}".'.format(f))
|
||||||
|
self.flags = _flags
|
||||||
|
|
||||||
def create_in_kernel(self):
|
def create_in_kernel(self):
|
||||||
"""Create the set, removing existing set if needed."""
|
"""Create the set, removing existing set if needed."""
|
||||||
# Delete set if it exists with wrong type
|
# Delete set if it exists with wrong type
|
||||||
|
@ -191,10 +226,11 @@ class NetfilterSet:
|
||||||
"""Create the non-existing set, creating table if needed."""
|
"""Create the non-existing set, creating table if needed."""
|
||||||
create_set = [
|
create_set = [
|
||||||
*self.nft,
|
*self.nft,
|
||||||
'add set {addr_family} {table} {set_} {{ type {type_} ; }}'.format(
|
'add set {addr_family} {table} {set_} {{ type {type_} ; flags {flags}}}'.format(
|
||||||
addr_family=self.address_family, table=self.table,
|
addr_family=self.address_family, table=self.table,
|
||||||
set_=self.name,
|
set_=self.name,
|
||||||
type_=' . '.join(self.TYPES[i] for i in self.type))
|
type_=' . '.join(self.TYPES[i] for i in self.type)),
|
||||||
|
flags=', '.join(self.flags)
|
||||||
]
|
]
|
||||||
return_code = CommandExec.run(create_set, allowed_return_codes=(0, 1))
|
return_code = CommandExec.run(create_set, allowed_return_codes=(0, 1))
|
||||||
if return_code == 0:
|
if return_code == 0:
|
||||||
|
|
188
nat.py
Normal file
188
nat.py
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Copyright © 2019 Hugo Levy-Falk <me@klafyvel.me>
|
||||||
|
|
||||||
|
"""
|
||||||
|
Creates the nat set.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
import netaddr
|
||||||
|
|
||||||
|
from firewall import NetfilterSet
|
||||||
|
|
||||||
|
CONFIG = ConfigParser()
|
||||||
|
CONFIG.read('config.ini')
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat(name, range_in, range_out, first_port, last_port):
|
||||||
|
"""Create two nftables tables for the nat:
|
||||||
|
- <name>_address : which link a (or a range of) local address to a
|
||||||
|
public address;
|
||||||
|
- <name>_port : which links a local address to a
|
||||||
|
range of ports.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: name of the sets
|
||||||
|
range_in: an IPRange with the private IP address
|
||||||
|
range_out: an IPRange with the public IP address
|
||||||
|
first_port: the first port used for the nat
|
||||||
|
last_port: the last port used for the nat
|
||||||
|
Returns:
|
||||||
|
(<name>_address, <name>_port) which are NetfilterSet
|
||||||
|
"""
|
||||||
|
assert last_port >= first_port, (name + ": Your first_port "
|
||||||
|
"is lower than your last_port")
|
||||||
|
nb_private_by_public = range_in.size / range_out.size
|
||||||
|
nb_port_by_ip = (last_port - first_port + 1) / nb_private_by_public
|
||||||
|
|
||||||
|
ports = []
|
||||||
|
ips = []
|
||||||
|
|
||||||
|
port = first_port
|
||||||
|
for ip, port in range_in:
|
||||||
|
ports.append((
|
||||||
|
str(netaddr.IPAddress(ip)),
|
||||||
|
"%d-%d" % (port, port+nb_port_by_ip)
|
||||||
|
))
|
||||||
|
port += nb_port_by_ip + 1
|
||||||
|
if port >= last_port:
|
||||||
|
port = first_port
|
||||||
|
ip = range_in.first
|
||||||
|
for ip_out in range_out:
|
||||||
|
ips.append((
|
||||||
|
'-'.join([
|
||||||
|
str(netaddr.IPAddress(ip)),
|
||||||
|
str(netaddr.IPAddress(ip+nb_private_by_public))
|
||||||
|
]),
|
||||||
|
str(ip_out)
|
||||||
|
))
|
||||||
|
ip += nb_private_by_public + 1
|
||||||
|
|
||||||
|
return (
|
||||||
|
NetfilterSet(
|
||||||
|
target_content=ips,
|
||||||
|
type_=('IPv4', 'IPv4'),
|
||||||
|
name=name,
|
||||||
|
table_name='nat',
|
||||||
|
),
|
||||||
|
NetfilterSet(
|
||||||
|
target_content=ports,
|
||||||
|
type_=('IPv4', 'port'),
|
||||||
|
name=name,
|
||||||
|
table_name='nat',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat_adherent():
|
||||||
|
range_in = netaddr.IPRange(CONFIG['range_in_adherent'])
|
||||||
|
range_out = netaddr.IPRange(CONFIG['range_out_adherent'])
|
||||||
|
first_port = CONFIG['first_port_adherent']
|
||||||
|
last_port = CONFIG['last_port_adherent']
|
||||||
|
return create_nat(
|
||||||
|
'adherent',
|
||||||
|
range_in,
|
||||||
|
range_out,
|
||||||
|
first_port,
|
||||||
|
last_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat_federez():
|
||||||
|
range_in = netaddr.IPRange(CONFIG['range_in_federez'])
|
||||||
|
range_out = netaddr.IPRange(CONFIG['range_out_federez'])
|
||||||
|
first_port = CONFIG['first_port_federez']
|
||||||
|
last_port = CONFIG['last_port_federez']
|
||||||
|
return create_nat(
|
||||||
|
'federez',
|
||||||
|
range_in,
|
||||||
|
range_out,
|
||||||
|
first_port,
|
||||||
|
last_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat_aloes():
|
||||||
|
range_in = netaddr.IPRange(CONFIG['range_in_aloes'])
|
||||||
|
range_out = netaddr.IPRange(CONFIG['range_out_aloes'])
|
||||||
|
first_port = CONFIG['first_port_aloes']
|
||||||
|
last_port = CONFIG['last_port_aloes']
|
||||||
|
return create_nat(
|
||||||
|
'aloes',
|
||||||
|
range_in,
|
||||||
|
range_out,
|
||||||
|
first_port,
|
||||||
|
last_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat_admin():
|
||||||
|
range_in = netaddr.IPRange(CONFIG['range_in_admin'])
|
||||||
|
range_out = netaddr.IPRange(CONFIG['range_out_admin'])
|
||||||
|
first_port = CONFIG['first_port_admin']
|
||||||
|
last_port = CONFIG['last_port_admin']
|
||||||
|
return create_nat(
|
||||||
|
'admin',
|
||||||
|
range_in,
|
||||||
|
range_out,
|
||||||
|
first_port,
|
||||||
|
last_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_nat_prerezotage():
|
||||||
|
range_in = netaddr.IPRange(CONFIG['range_in_prerezotage'])
|
||||||
|
range_out = netaddr.IPRange(CONFIG['range_out_prerezotage'])
|
||||||
|
first_port = CONFIG['first_port_prerezotage']
|
||||||
|
last_port = CONFIG['last_port_prerezotage']
|
||||||
|
return create_nat(
|
||||||
|
'prerezotage',
|
||||||
|
range_in,
|
||||||
|
range_out,
|
||||||
|
first_port,
|
||||||
|
last_port
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logging.info("Creating adherent nat...")
|
||||||
|
address, port = create_nat_adherent()
|
||||||
|
address.manage()
|
||||||
|
port.manage()
|
||||||
|
logging.info("Done.")
|
||||||
|
logging.info("Creating federez nat...")
|
||||||
|
address, port = create_nat_federez()
|
||||||
|
address.manage()
|
||||||
|
port.manage()
|
||||||
|
logging.info("Done.")
|
||||||
|
logging.info("Creating aloes nat...")
|
||||||
|
address, port = create_nat_aloes()
|
||||||
|
address.manage()
|
||||||
|
port.manage()
|
||||||
|
logging.info("Done.")
|
||||||
|
logging.info("Creating admin nat...")
|
||||||
|
address, port = create_nat_admin()
|
||||||
|
address.manage()
|
||||||
|
port.manage()
|
||||||
|
logging.info("Done.")
|
||||||
|
logging.info("Creating prerezotage nat...")
|
||||||
|
address, port = create_nat_prerezotage()
|
||||||
|
address.manage()
|
||||||
|
port.manage()
|
||||||
|
logging.info("Done.")
|
Loading…
Reference in a new issue