feat: complete snat with all shorewall columns (proto, port, ipsec, mark, user, switch, origdest, probability)
All checks were successful
Build containers when image tags change / build-if-image-changed (frontend, shorefront-frontend, shorefront frontend, frontend/Dockerfile, git.baumann.gr/adebaumann/shorefront-frontend, .frontend.image) (push) Successful in 1m14s
Build containers when image tags change / build-if-image-changed (backend, shorefront-backend, shorefront backend, backend/Dockerfile, git.baumann.gr/adebaumann/shorefront-backend, .backend.image) (push) Successful in 2m2s
All checks were successful
Build containers when image tags change / build-if-image-changed (frontend, shorefront-frontend, shorefront frontend, frontend/Dockerfile, git.baumann.gr/adebaumann/shorefront-frontend, .frontend.image) (push) Successful in 1m14s
Build containers when image tags change / build-if-image-changed (backend, shorefront-backend, shorefront backend, backend/Dockerfile, git.baumann.gr/adebaumann/shorefront-backend, .backend.image) (push) Successful in 2m2s
This commit is contained in:
34
backend/alembic/versions/0010_snat_add_missing_columns.py
Normal file
34
backend/alembic/versions/0010_snat_add_missing_columns.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""add missing shorewall snat columns
|
||||
|
||||
Revision ID: 0010
|
||||
Revises: 0009
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0010"
|
||||
down_revision = "0009"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
_NEW_COLS = [
|
||||
("proto", sa.String(16)),
|
||||
("port", sa.String(64)),
|
||||
("ipsec", sa.String(128)),
|
||||
("mark", sa.String(32)),
|
||||
("user_group", sa.String(64)),
|
||||
("switch_name", sa.String(32)),
|
||||
("origdest", sa.String(128)),
|
||||
("probability", sa.String(16)),
|
||||
]
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
for col_name, col_type in _NEW_COLS:
|
||||
op.add_column("snat", sa.Column(col_name, col_type, server_default="''", nullable=False))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
for col_name, _ in reversed(_NEW_COLS):
|
||||
op.drop_column("snat", col_name)
|
||||
@@ -124,6 +124,14 @@ class Snat(Base):
|
||||
source_network: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
out_interface: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
to_address: Mapped[str] = mapped_column(String(64), default="")
|
||||
proto: Mapped[str] = mapped_column(String(16), default="")
|
||||
port: Mapped[str] = mapped_column(String(64), default="")
|
||||
ipsec: Mapped[str] = mapped_column(String(128), default="")
|
||||
mark: Mapped[str] = mapped_column(String(32), default="")
|
||||
user_group: Mapped[str] = mapped_column(String(64), default="")
|
||||
switch_name: Mapped[str] = mapped_column(String(32), default="")
|
||||
origdest: Mapped[str] = mapped_column(String(128), default="")
|
||||
probability: Mapped[str] = mapped_column(String(16), default="")
|
||||
comment: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
config: Mapped["Config"] = relationship("Config", back_populates="snat_entries")
|
||||
|
||||
@@ -201,6 +201,14 @@ class SnatCreate(BaseModel):
|
||||
source_network: str
|
||||
out_interface: str
|
||||
to_address: str = ""
|
||||
proto: str = ""
|
||||
port: str = ""
|
||||
ipsec: str = ""
|
||||
mark: str = ""
|
||||
user_group: str = ""
|
||||
switch_name: str = ""
|
||||
origdest: str = ""
|
||||
probability: str = ""
|
||||
comment: str = ""
|
||||
|
||||
|
||||
@@ -208,6 +216,14 @@ class SnatUpdate(BaseModel):
|
||||
source_network: Optional[str] = None
|
||||
out_interface: Optional[str] = None
|
||||
to_address: Optional[str] = None
|
||||
proto: Optional[str] = None
|
||||
port: Optional[str] = None
|
||||
ipsec: Optional[str] = None
|
||||
mark: Optional[str] = None
|
||||
user_group: Optional[str] = None
|
||||
switch_name: Optional[str] = None
|
||||
origdest: Optional[str] = None
|
||||
probability: Optional[str] = None
|
||||
comment: Optional[str] = None
|
||||
|
||||
|
||||
@@ -217,6 +233,14 @@ class SnatOut(BaseModel):
|
||||
source_network: str
|
||||
out_interface: str
|
||||
to_address: str
|
||||
proto: str
|
||||
port: str
|
||||
ipsec: str
|
||||
mark: str
|
||||
user_group: str
|
||||
switch_name: str
|
||||
origdest: str
|
||||
probability: str
|
||||
comment: str
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
@@ -87,10 +87,22 @@ class ShorewallGenerator:
|
||||
return "".join(lines)
|
||||
|
||||
def snat(self) -> str:
|
||||
lines = [self._header("snat"), "#ACTION".ljust(24) + "SOURCE".ljust(24) + "DEST\n"]
|
||||
lines = [
|
||||
self._header("snat"),
|
||||
"#ACTION".ljust(24) + "SOURCE".ljust(24) + "DEST".ljust(20)
|
||||
+ "PROTO".ljust(10) + "PORT".ljust(16) + "IPSEC".ljust(16)
|
||||
+ "MARK".ljust(12) + "USER/GROUP".ljust(16) + "SWITCH".ljust(16)
|
||||
+ "ORIGDEST".ljust(20) + "PROBABILITY\n",
|
||||
]
|
||||
for m in self._config.snat_entries:
|
||||
action = f"SNAT:{m.to_address}" if m.to_address else "MASQUERADE"
|
||||
lines.append(self._col(action, m.source_network, m.out_interface, width=24))
|
||||
lines.append(self._col(
|
||||
action, m.source_network, m.out_interface,
|
||||
m.proto or "-", m.port or "-", m.ipsec or "-",
|
||||
m.mark or "-", m.user_group or "-", m.switch_name or "-",
|
||||
m.origdest or "-", m.probability or "-",
|
||||
width=16,
|
||||
))
|
||||
return "".join(lines)
|
||||
|
||||
def as_json(self) -> dict:
|
||||
|
||||
@@ -19,7 +19,7 @@ interface Zone { id: number; name: string; type: string; options: string }
|
||||
interface Iface { id: number; name: string; zone_id: number; options: string }
|
||||
interface Policy { id: number; src_zone_id: number; dst_zone_id: number; policy: string; log_level: string; comment: string; position: number }
|
||||
interface Rule { id: number; action: string; src_zone_id: number | null; dst_zone_id: number | null; src_ip: string; dst_ip: string; proto: string; dport: string; sport: string; origdest: string; rate_limit: string; user_group: string; mark: string; connlimit: string; time: string; headers: string; switch_name: string; helper: string; comment: string; position: number }
|
||||
interface Snat { id: number; source_network: string; out_interface: string; to_address: string; comment: string }
|
||||
interface Snat { id: number; source_network: string; out_interface: string; to_address: string; proto: string; port: string; ipsec: string; mark: string; user_group: string; switch_name: string; origdest: string; probability: string; comment: string }
|
||||
interface Host { id: number; zone_id: number; interface: string; subnet: string; options: string }
|
||||
interface Param { id: number; name: string; value: string }
|
||||
|
||||
@@ -194,12 +194,21 @@ export default function ConfigDetail() {
|
||||
{ key: 'out_interface' as const, label: 'Out Interface' },
|
||||
{ key: 'source_network' as const, label: 'Source Network' },
|
||||
{ key: 'to_address' as const, label: 'To Address' },
|
||||
{ key: 'comment' as const, label: 'Comment' },
|
||||
{ key: 'proto' as const, label: 'Proto' },
|
||||
{ key: 'probability' as const, label: 'Probability' },
|
||||
] as Column<AnyEntity>[],
|
||||
fields: [
|
||||
{ name: 'out_interface', label: 'Out Interface', required: true },
|
||||
{ name: 'source_network', label: 'Source Network', required: true },
|
||||
{ name: 'to_address', label: 'To Address' },
|
||||
{ name: 'to_address', label: 'To Address (blank = MASQUERADE)', placeholder: 'e.g. 1.2.3.4' },
|
||||
{ name: 'proto', label: 'Protocol', placeholder: 'e.g. tcp, udp' },
|
||||
{ name: 'port', label: 'Port', placeholder: 'e.g. 80, 1024:65535' },
|
||||
{ name: 'ipsec', label: 'IPsec', placeholder: 'e.g. mode=tunnel' },
|
||||
{ name: 'mark', label: 'Mark', placeholder: 'e.g. 0x100/0xff0' },
|
||||
{ name: 'user_group', label: 'User/Group', placeholder: 'e.g. joe:wheel' },
|
||||
{ name: 'switch_name', label: 'Switch', placeholder: 'e.g. vpn_enabled' },
|
||||
{ name: 'origdest', label: 'Orig Dest', placeholder: 'e.g. 1.2.3.4' },
|
||||
{ name: 'probability', label: 'Probability', placeholder: 'e.g. 0.25' },
|
||||
{ name: 'comment', label: 'Comment' },
|
||||
] as FieldDef[],
|
||||
},
|
||||
|
||||
@@ -42,4 +42,4 @@ keycloak:
|
||||
redirectUri: https://shorefront.baumann.gr/api/auth/oidc/callback
|
||||
|
||||
containers:
|
||||
version: "0.008"
|
||||
version: "0.009"
|
||||
|
||||
Reference in New Issue
Block a user