works enough for now
This commit is contained in:
commit
c04a9a752a
12 changed files with 178 additions and 0 deletions
5
compiler/__init__.py
Normal file
5
compiler/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from .parser import load_services, load_globals
|
||||
from .nat import build_nat_rules
|
||||
from .firewall import build_firewall_rules
|
||||
from .dns import build_dns
|
||||
from .render import render_nat
|
||||
6
compiler/dns.py
Normal file
6
compiler/dns.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
def build_dns(services, cfg):
|
||||
return([
|
||||
{"name": s.name, "ip": s.internal_ip}
|
||||
for s in services
|
||||
if "dns" in s.exposure
|
||||
])
|
||||
9
compiler/firewall.py
Normal file
9
compiler/firewall.py
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
def build_firewall_rules(services, cfg):
|
||||
rules = []
|
||||
for s in services:
|
||||
if "nat" in s.exposure:
|
||||
rules.append({
|
||||
"service": s.name,
|
||||
"allow_port": s.public_port,
|
||||
})
|
||||
return(rules)
|
||||
17
compiler/models.py
Normal file
17
compiler/models.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from dataclasses import dataclass
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Service:
|
||||
name: str
|
||||
internal_ip: str
|
||||
internal_port: int
|
||||
public_port: int
|
||||
protocol: str
|
||||
exposure: set[str]
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GlobalConfig:
|
||||
wan_interface: str
|
||||
public_ip: str
|
||||
lan_interface: str
|
||||
internal_cidr: str
|
||||
29
compiler/nat.py
Normal file
29
compiler/nat.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import hashlib
|
||||
|
||||
def rule_id(service_name: str, kind: str) -> int:
|
||||
h = hashlib.sha1(f"{service_name}:{kind}".encode()).hexdigest()
|
||||
return(int(h[:4], 16)) # here's hoping
|
||||
|
||||
def build_nat_rules(services, cfg):
|
||||
rules = []
|
||||
|
||||
for s in services:
|
||||
rid_wan = rule_id(s.name, "dnat_wan")
|
||||
rid_hairpin = rule_id(s.name, "dnat_hairpin")
|
||||
|
||||
rules.append({
|
||||
"id": rid_wan,
|
||||
"service": s,
|
||||
"cfg": cfg,
|
||||
"kind": "dnat_wan",
|
||||
})
|
||||
|
||||
if "nat" in s.exposure:
|
||||
rules.append({
|
||||
"id": rid_hairpin,
|
||||
"service": s,
|
||||
"cfg": cfg,
|
||||
"kind": "dnat_hairpin",
|
||||
})
|
||||
|
||||
return(rules)
|
||||
27
compiler/parser.py
Normal file
27
compiler/parser.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import yaml
|
||||
from .models import GlobalConfig, Service
|
||||
|
||||
def load_services(path: str) -> list[Service]:
|
||||
raw = yaml.safe_load(open(path))["services"]
|
||||
|
||||
services = []
|
||||
for name, s in raw.items():
|
||||
ip, port = s["endpoint"].split(":")
|
||||
services.append(Service(
|
||||
name=name,
|
||||
internal_ip=ip,
|
||||
internal_port=int(port),
|
||||
public_port=int(s["public_port"]),
|
||||
protocol=s["protocol"],
|
||||
exposure=set(s.get("exposure", [])),
|
||||
))
|
||||
return(services)
|
||||
|
||||
def load_globals(path: str) -> GlobalConfig:
|
||||
g = yaml.safe_load(open(path))["wan"]
|
||||
return GlobalConfig(
|
||||
wan_interface=g["wan_interface"],
|
||||
public_ip=g["public_ip"],
|
||||
lan_interface=g["lan_interface"],
|
||||
internal_cidr=g["internal_cidr"],
|
||||
)
|
||||
7
compiler/render.py
Normal file
7
compiler/render.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
env = Environment(loader=FileSystemLoader("templates"))
|
||||
|
||||
def render_nat(rules):
|
||||
tmpl = env.get_template("vyos_nat.j2")
|
||||
return(tmpl.render(rules=rules))
|
||||
Loading…
Add table
Add a link
Reference in a new issue