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 {
|
||||
# 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
|
||||
}
|
||||
|
|
50
firewall.py
50
firewall.py
|
@ -89,12 +89,35 @@ class Parser:
|
|||
return netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded)
|
||||
@staticmethod
|
||||
def IPv4(ip):
|
||||
"""Check an IPv4 validity."""
|
||||
return netaddr.IPAddress(ip, version=4)
|
||||
"""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)
|
||||
except ValueError:
|
||||
return netaddr.IPNetwork(ip, version=4)
|
||||
@staticmethod
|
||||
def IPv6(ip):
|
||||
"""Check a IPv6 validity."""
|
||||
return netaddr.IPAddress(ip, version=6)
|
||||
"""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)
|
||||
except ValueError:
|
||||
return netaddr.IPNetwork(ip, version=6)
|
||||
|
||||
@staticmethod
|
||||
def protocol(protocol):
|
||||
"""Check a protocol validity."""
|
||||
|
@ -120,13 +143,17 @@ class NetfilterSet:
|
|||
|
||||
ADDRESS_FAMILIES = {'ip', 'ip6', 'inet', 'arp', 'bridge', 'netdev'}
|
||||
|
||||
FLAGS = {'constant', 'interval', 'timeout'}
|
||||
|
||||
def __init__(self,
|
||||
name,
|
||||
type_, # e.g.: ('MAC', 'IPv4')
|
||||
target_content=None,
|
||||
use_sudo=True,
|
||||
address_family='inet', # Manage both IPv4 and IPv6.
|
||||
table_name='filter'):
|
||||
table_name='filter',
|
||||
flags = []
|
||||
):
|
||||
self.name = name
|
||||
self.content = set()
|
||||
# self.type
|
||||
|
@ -135,6 +162,7 @@ class NetfilterSet:
|
|||
# self.address_family
|
||||
self.set_address_family(address_family)
|
||||
self.table = table_name
|
||||
self.set_flags(flags)
|
||||
sudo = ["/usr/bin/sudo"] * int(bool(use_sudo))
|
||||
self.nft = [*sudo, "/usr/sbin/nft"]
|
||||
if target_content:
|
||||
|
@ -167,6 +195,13 @@ class NetfilterSet:
|
|||
'Invalid address_family: "{}".'.format(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):
|
||||
"""Create the set, removing existing set if needed."""
|
||||
# Delete set if it exists with wrong type
|
||||
|
@ -191,10 +226,11 @@ class NetfilterSet:
|
|||
"""Create the non-existing set, creating table if needed."""
|
||||
create_set = [
|
||||
*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,
|
||||
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))
|
||||
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