Compare commits
7 Commits
21d404229a
...
02c8f71957
| Author | SHA1 | Date | |
|---|---|---|---|
| 02c8f71957 | |||
| 36224cebcd | |||
| 3c259a1862 | |||
| e05e9d5975 | |||
| 3dc97df6cd | |||
| 8b787a99c2 | |||
| 58ef0dec63 |
21
backend/alembic/versions/0005_interface_zone_nullable.py
Normal file
21
backend/alembic/versions/0005_interface_zone_nullable.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""make interface zone_id nullable
|
||||
|
||||
Revision ID: 0005
|
||||
Revises: 0004
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0005"
|
||||
down_revision = "0004"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.alter_column("interfaces", "zone_id", existing_type=sa.Integer(), nullable=True)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.alter_column("interfaces", "zone_id", existing_type=sa.Integer(), nullable=False)
|
||||
21
backend/alembic/versions/0006_interface_add_broadcast.py
Normal file
21
backend/alembic/versions/0006_interface_add_broadcast.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""add broadcast column to interfaces
|
||||
|
||||
Revision ID: 0006
|
||||
Revises: 0005
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0006"
|
||||
down_revision = "0005"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("interfaces", sa.Column("broadcast", sa.String(64), server_default="''", nullable=False))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("interfaces", "broadcast")
|
||||
23
backend/alembic/versions/0007_policy_zones_nullable.py
Normal file
23
backend/alembic/versions/0007_policy_zones_nullable.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""make policy zone ids nullable (support 'all')
|
||||
|
||||
Revision ID: 0007
|
||||
Revises: 0006
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0007"
|
||||
down_revision = "0006"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.alter_column("policies", "src_zone_id", existing_type=sa.Integer(), nullable=True)
|
||||
op.alter_column("policies", "dst_zone_id", existing_type=sa.Integer(), nullable=True)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.alter_column("policies", "src_zone_id", existing_type=sa.Integer(), nullable=False)
|
||||
op.alter_column("policies", "dst_zone_id", existing_type=sa.Integer(), nullable=False)
|
||||
23
backend/alembic/versions/0008_policy_add_limit_connlimit.py
Normal file
23
backend/alembic/versions/0008_policy_add_limit_connlimit.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""add limit_burst and connlimit_mask to policies
|
||||
|
||||
Revision ID: 0008
|
||||
Revises: 0007
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0008"
|
||||
down_revision = "0007"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("policies", sa.Column("limit_burst", sa.String(64), server_default="''", nullable=False))
|
||||
op.add_column("policies", sa.Column("connlimit_mask", sa.String(32), server_default="''", nullable=False))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("policies", "connlimit_mask")
|
||||
op.drop_column("policies", "limit_burst")
|
||||
35
backend/alembic/versions/0009_rules_add_missing_columns.py
Normal file
35
backend/alembic/versions/0009_rules_add_missing_columns.py
Normal file
@@ -0,0 +1,35 @@
|
||||
"""add missing shorewall rule columns
|
||||
|
||||
Revision ID: 0009
|
||||
Revises: 0008
|
||||
Create Date: 2026-03-01
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "0009"
|
||||
down_revision = "0008"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
_NEW_COLS = [
|
||||
("origdest", sa.String(128)),
|
||||
("rate_limit", sa.String(64)),
|
||||
("user_group", sa.String(64)),
|
||||
("mark", sa.String(32)),
|
||||
("connlimit", sa.String(32)),
|
||||
("time", sa.String(128)),
|
||||
("headers", sa.String(128)),
|
||||
("switch_name", sa.String(32)),
|
||||
("helper", sa.String(32)),
|
||||
]
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
for col_name, col_type in _NEW_COLS:
|
||||
op.add_column("rules", sa.Column(col_name, col_type, server_default="''", nullable=False))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
for col_name, _ in reversed(_NEW_COLS):
|
||||
op.drop_column("rules", col_name)
|
||||
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)
|
||||
@@ -59,11 +59,12 @@ class Interface(Base):
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
zone_id: Mapped[int] = mapped_column(Integer, ForeignKey("zones.id"), nullable=False)
|
||||
zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True)
|
||||
broadcast: Mapped[str] = mapped_column(String(64), default="")
|
||||
options: Mapped[str] = mapped_column(Text, default="")
|
||||
|
||||
config: Mapped["Config"] = relationship("Config", back_populates="interfaces")
|
||||
zone: Mapped["Zone"] = relationship("Zone", back_populates="interfaces")
|
||||
zone: Mapped["Zone | None"] = relationship("Zone", back_populates="interfaces")
|
||||
|
||||
|
||||
class Policy(Base):
|
||||
@@ -71,16 +72,18 @@ class Policy(Base):
|
||||
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
config_id: Mapped[int] = mapped_column(Integer, ForeignKey("configs.id"), nullable=False)
|
||||
src_zone_id: Mapped[int] = mapped_column(Integer, ForeignKey("zones.id"), nullable=False)
|
||||
dst_zone_id: Mapped[int] = mapped_column(Integer, ForeignKey("zones.id"), nullable=False)
|
||||
src_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True)
|
||||
dst_zone_id: Mapped[int | None] = mapped_column(Integer, ForeignKey("zones.id"), nullable=True)
|
||||
policy: Mapped[str] = mapped_column(String(16), nullable=False)
|
||||
log_level: Mapped[str] = mapped_column(String(16), default="")
|
||||
limit_burst: Mapped[str] = mapped_column(String(64), default="")
|
||||
connlimit_mask: Mapped[str] = mapped_column(String(32), default="")
|
||||
comment: Mapped[str] = mapped_column(Text, default="")
|
||||
position: Mapped[int] = mapped_column(Integer, default=0)
|
||||
|
||||
config: Mapped["Config"] = relationship("Config", back_populates="policies")
|
||||
src_zone: Mapped["Zone"] = relationship("Zone", foreign_keys=[src_zone_id])
|
||||
dst_zone: Mapped["Zone"] = relationship("Zone", foreign_keys=[dst_zone_id])
|
||||
src_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[src_zone_id])
|
||||
dst_zone: Mapped["Zone | None"] = relationship("Zone", foreign_keys=[dst_zone_id])
|
||||
|
||||
|
||||
class Rule(Base):
|
||||
@@ -96,6 +99,15 @@ class Rule(Base):
|
||||
proto: Mapped[str] = mapped_column(String(16), default="")
|
||||
dport: Mapped[str] = mapped_column(String(64), default="")
|
||||
sport: Mapped[str] = mapped_column(String(64), default="")
|
||||
origdest: Mapped[str] = mapped_column(String(128), default="")
|
||||
rate_limit: Mapped[str] = mapped_column(String(64), default="")
|
||||
user_group: Mapped[str] = mapped_column(String(64), default="")
|
||||
mark: Mapped[str] = mapped_column(String(32), default="")
|
||||
connlimit: Mapped[str] = mapped_column(String(32), default="")
|
||||
time: Mapped[str] = mapped_column(String(128), default="")
|
||||
headers: Mapped[str] = mapped_column(String(128), default="")
|
||||
switch_name: Mapped[str] = mapped_column(String(32), default="")
|
||||
helper: Mapped[str] = mapped_column(String(32), default="")
|
||||
comment: Mapped[str] = mapped_column(Text, default="")
|
||||
position: Mapped[int] = mapped_column(Integer, default=0)
|
||||
|
||||
@@ -112,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")
|
||||
|
||||
@@ -64,13 +64,15 @@ class ZoneOut(BaseModel):
|
||||
# --- Interface ---
|
||||
class InterfaceCreate(BaseModel):
|
||||
name: str
|
||||
zone_id: int
|
||||
zone_id: Optional[int] = None
|
||||
broadcast: str = ""
|
||||
options: str = ""
|
||||
|
||||
|
||||
class InterfaceUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
zone_id: Optional[int] = None
|
||||
broadcast: Optional[str] = None
|
||||
options: Optional[str] = None
|
||||
|
||||
|
||||
@@ -78,7 +80,8 @@ class InterfaceOut(BaseModel):
|
||||
id: int
|
||||
config_id: int
|
||||
name: str
|
||||
zone_id: int
|
||||
zone_id: Optional[int]
|
||||
broadcast: str
|
||||
options: str
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
@@ -86,10 +89,12 @@ class InterfaceOut(BaseModel):
|
||||
|
||||
# --- Policy ---
|
||||
class PolicyCreate(BaseModel):
|
||||
src_zone_id: int
|
||||
dst_zone_id: int
|
||||
src_zone_id: Optional[int] = None
|
||||
dst_zone_id: Optional[int] = None
|
||||
policy: str
|
||||
log_level: str = ""
|
||||
limit_burst: str = ""
|
||||
connlimit_mask: str = ""
|
||||
comment: str = ""
|
||||
position: int = 0
|
||||
|
||||
@@ -99,6 +104,8 @@ class PolicyUpdate(BaseModel):
|
||||
dst_zone_id: Optional[int] = None
|
||||
policy: Optional[str] = None
|
||||
log_level: Optional[str] = None
|
||||
limit_burst: Optional[str] = None
|
||||
connlimit_mask: Optional[str] = None
|
||||
comment: Optional[str] = None
|
||||
position: Optional[int] = None
|
||||
|
||||
@@ -106,10 +113,12 @@ class PolicyUpdate(BaseModel):
|
||||
class PolicyOut(BaseModel):
|
||||
id: int
|
||||
config_id: int
|
||||
src_zone_id: int
|
||||
dst_zone_id: int
|
||||
src_zone_id: Optional[int]
|
||||
dst_zone_id: Optional[int]
|
||||
policy: str
|
||||
log_level: str
|
||||
limit_burst: str
|
||||
connlimit_mask: str
|
||||
comment: str
|
||||
position: int
|
||||
|
||||
@@ -126,6 +135,15 @@ class RuleCreate(BaseModel):
|
||||
proto: str = ""
|
||||
dport: str = ""
|
||||
sport: str = ""
|
||||
origdest: str = ""
|
||||
rate_limit: str = ""
|
||||
user_group: str = ""
|
||||
mark: str = ""
|
||||
connlimit: str = ""
|
||||
time: str = ""
|
||||
headers: str = ""
|
||||
switch_name: str = ""
|
||||
helper: str = ""
|
||||
comment: str = ""
|
||||
position: int = 0
|
||||
|
||||
@@ -139,6 +157,15 @@ class RuleUpdate(BaseModel):
|
||||
proto: Optional[str] = None
|
||||
dport: Optional[str] = None
|
||||
sport: Optional[str] = None
|
||||
origdest: Optional[str] = None
|
||||
rate_limit: Optional[str] = None
|
||||
user_group: Optional[str] = None
|
||||
mark: Optional[str] = None
|
||||
connlimit: Optional[str] = None
|
||||
time: Optional[str] = None
|
||||
headers: Optional[str] = None
|
||||
switch_name: Optional[str] = None
|
||||
helper: Optional[str] = None
|
||||
comment: Optional[str] = None
|
||||
position: Optional[int] = None
|
||||
|
||||
@@ -154,6 +181,15 @@ class RuleOut(BaseModel):
|
||||
proto: str
|
||||
dport: str
|
||||
sport: str
|
||||
origdest: str
|
||||
rate_limit: str
|
||||
user_group: str
|
||||
mark: str
|
||||
connlimit: str
|
||||
time: str
|
||||
headers: str
|
||||
switch_name: str
|
||||
helper: str
|
||||
comment: str
|
||||
position: int
|
||||
|
||||
@@ -165,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 = ""
|
||||
|
||||
|
||||
@@ -172,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
|
||||
|
||||
|
||||
@@ -181,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}
|
||||
|
||||
@@ -26,27 +26,51 @@ class ShorewallGenerator:
|
||||
return "".join(lines)
|
||||
|
||||
def interfaces(self) -> str:
|
||||
lines = [self._header("interfaces"), "#ZONE".ljust(16) + "INTERFACE".ljust(16) + "OPTIONS\n"]
|
||||
lines = [self._header("interfaces"), "#ZONE".ljust(16) + "INTERFACE".ljust(16) + "BROADCAST".ljust(16) + "OPTIONS\n"]
|
||||
for iface in self._config.interfaces:
|
||||
lines.append(self._col(iface.zone.name, iface.name, iface.options or "-"))
|
||||
zone = iface.zone.name if iface.zone else "-"
|
||||
lines.append(self._col(zone, iface.name, iface.broadcast or "-", iface.options or "-"))
|
||||
return "".join(lines)
|
||||
|
||||
def policy(self) -> str:
|
||||
lines = [self._header("policy"), "#SOURCE".ljust(16) + "DEST".ljust(16) + "POLICY".ljust(16) + "LOG LEVEL\n"]
|
||||
lines = [
|
||||
self._header("policy"),
|
||||
"#SOURCE".ljust(16) + "DEST".ljust(16) + "POLICY".ljust(16)
|
||||
+ "LOG LEVEL".ljust(16) + "LIMIT:BURST".ljust(20) + "CONNLIMIT:MASK\n",
|
||||
]
|
||||
for p in sorted(self._config.policies, key=lambda x: x.position):
|
||||
lines.append(self._col(p.src_zone.name, p.dst_zone.name, p.policy, p.log_level or "-"))
|
||||
src = p.src_zone.name if p.src_zone else "all"
|
||||
dst = p.dst_zone.name if p.dst_zone else "all"
|
||||
lines.append(self._col(
|
||||
src, dst, p.policy,
|
||||
p.log_level or "-",
|
||||
p.limit_burst or "-",
|
||||
p.connlimit_mask or "-",
|
||||
width=16,
|
||||
))
|
||||
return "".join(lines)
|
||||
|
||||
def rules(self) -> str:
|
||||
lines = [
|
||||
self._header("rules"),
|
||||
"#ACTION".ljust(16) + "SOURCE".ljust(24) + "DEST".ljust(24) + "PROTO".ljust(10) + "DPORT".ljust(10) + "SPORT\n",
|
||||
"#ACTION".ljust(16) + "SOURCE".ljust(24) + "DEST".ljust(24)
|
||||
+ "PROTO".ljust(10) + "DPORT".ljust(16) + "SPORT".ljust(16)
|
||||
+ "ORIGDEST".ljust(20) + "RATE".ljust(16) + "USER".ljust(16)
|
||||
+ "MARK".ljust(12) + "CONNLIMIT".ljust(14) + "TIME".ljust(20)
|
||||
+ "HEADERS".ljust(16) + "SWITCH".ljust(16) + "HELPER\n",
|
||||
"SECTION NEW\n",
|
||||
]
|
||||
for r in sorted(self._config.rules, key=lambda x: x.position):
|
||||
src = (r.src_zone.name if r.src_zone else "all") + (f":{r.src_ip}" if r.src_ip else "")
|
||||
dst = (r.dst_zone.name if r.dst_zone else "all") + (f":{r.dst_ip}" if r.dst_ip else "")
|
||||
lines.append(self._col(r.action, src, dst, r.proto or "-", r.dport or "-", r.sport or "-", width=16))
|
||||
lines.append(self._col(
|
||||
r.action, src, dst,
|
||||
r.proto or "-", r.dport or "-", r.sport or "-",
|
||||
r.origdest or "-", r.rate_limit or "-", r.user_group or "-",
|
||||
r.mark or "-", r.connlimit or "-", r.time or "-",
|
||||
r.headers or "-", r.switch_name or "-", r.helper or "-",
|
||||
width=16,
|
||||
))
|
||||
return "".join(lines)
|
||||
|
||||
def hosts(self) -> str:
|
||||
@@ -63,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:
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface FieldDef {
|
||||
required?: boolean
|
||||
type?: 'text' | 'select' | 'number'
|
||||
options?: { value: string | number; label: string }[]
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@@ -67,6 +68,7 @@ export default function EntityForm({ open, title, fields, initialValues, onClose
|
||||
value={values[f.name] ?? ''}
|
||||
onChange={(e) => handleChange(f.name, e.target.value)}
|
||||
size="small"
|
||||
placeholder={f.placeholder}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -18,8 +18,8 @@ import { zonesApi, interfacesApi, policiesApi, rulesApi, snatApi, hostsApi, para
|
||||
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; comment: string; position: number }
|
||||
interface Snat { id: number; source_network: string; out_interface: string; to_address: string; comment: string }
|
||||
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; 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 }
|
||||
|
||||
@@ -83,13 +83,15 @@ export default function ConfigDetail() {
|
||||
{
|
||||
key: 'zone_id' as const,
|
||||
label: 'Zone',
|
||||
render: (r: AnyEntity) => zones.find((z) => z.id === r['zone_id'])?.name ?? String(r['zone_id']),
|
||||
render: (r: AnyEntity) => r['zone_id'] == null ? '-' : (zones.find((z) => z.id === r['zone_id'])?.name ?? String(r['zone_id'])),
|
||||
},
|
||||
{ key: 'broadcast' as const, label: 'Broadcast' },
|
||||
{ key: 'options' as const, label: 'Options' },
|
||||
] as Column<AnyEntity>[],
|
||||
fields: [
|
||||
{ name: 'name', label: 'Interface Name', required: true },
|
||||
{ name: 'zone_id', label: 'Zone', required: true, type: 'select' as const, options: zoneOptions },
|
||||
{ name: 'zone_id', label: 'Zone', type: 'select' as const, options: [{ value: '', label: '- (no zone)' }, ...zoneOptions] },
|
||||
{ name: 'broadcast', label: 'Broadcast' },
|
||||
{ name: 'options', label: 'Options' },
|
||||
] as FieldDef[],
|
||||
},
|
||||
@@ -102,22 +104,26 @@ export default function ConfigDetail() {
|
||||
{
|
||||
key: 'src_zone_id' as const,
|
||||
label: 'Source',
|
||||
render: (r: AnyEntity) => zones.find((z) => z.id === r['src_zone_id'])?.name ?? String(r['src_zone_id']),
|
||||
render: (r: AnyEntity) => r['src_zone_id'] == null ? 'all' : (zones.find((z) => z.id === r['src_zone_id'])?.name ?? String(r['src_zone_id'])),
|
||||
},
|
||||
{
|
||||
key: 'dst_zone_id' as const,
|
||||
label: 'Destination',
|
||||
render: (r: AnyEntity) => zones.find((z) => z.id === r['dst_zone_id'])?.name ?? String(r['dst_zone_id']),
|
||||
render: (r: AnyEntity) => r['dst_zone_id'] == null ? 'all' : (zones.find((z) => z.id === r['dst_zone_id'])?.name ?? String(r['dst_zone_id'])),
|
||||
},
|
||||
{ key: 'policy' as const, label: 'Policy' },
|
||||
{ key: 'log_level' as const, label: 'Log Level' },
|
||||
{ key: 'limit_burst' as const, label: 'Limit:Burst' },
|
||||
{ key: 'connlimit_mask' as const, label: 'ConnLimit:Mask' },
|
||||
{ key: 'position' as const, label: 'Position' },
|
||||
] as Column<AnyEntity>[],
|
||||
fields: [
|
||||
{ name: 'src_zone_id', label: 'Source Zone', required: true, type: 'select' as const, options: zoneOptions },
|
||||
{ name: 'dst_zone_id', label: 'Destination Zone', required: true, type: 'select' as const, options: zoneOptions },
|
||||
{ name: 'src_zone_id', label: 'Source Zone', type: 'select' as const, options: [{ value: '', label: 'all' }, ...zoneOptions] },
|
||||
{ name: 'dst_zone_id', label: 'Destination Zone', type: 'select' as const, options: [{ value: '', label: 'all' }, ...zoneOptions] },
|
||||
{ name: 'policy', label: 'Policy', required: true, type: 'select' as const, options: [{ value: 'ACCEPT', label: 'ACCEPT' }, { value: 'DROP', label: 'DROP' }, { value: 'REJECT', label: 'REJECT' }, { value: 'CONTINUE', label: 'CONTINUE' }] },
|
||||
{ name: 'log_level', label: 'Log Level' },
|
||||
{ name: 'limit_burst', label: 'Limit:Burst', placeholder: 'e.g. 10/sec:20' },
|
||||
{ name: 'connlimit_mask', label: 'ConnLimit:Mask', placeholder: 'e.g. 10:24' },
|
||||
{ name: 'comment', label: 'Comment' },
|
||||
{ name: 'position', label: 'Position', type: 'number' as const },
|
||||
] as FieldDef[],
|
||||
@@ -141,17 +147,40 @@ export default function ConfigDetail() {
|
||||
},
|
||||
{ key: 'proto' as const, label: 'Proto' },
|
||||
{ key: 'dport' as const, label: 'DPort' },
|
||||
{ key: 'origdest' as const, label: 'OrigDest' },
|
||||
{ key: 'position' as const, label: 'Position' },
|
||||
] as Column<AnyEntity>[],
|
||||
fields: [
|
||||
{ name: 'action', label: 'Action', required: true },
|
||||
{ name: 'src_zone_id', label: 'Source Zone', type: 'select' as const, options: zoneOptions },
|
||||
{ name: 'dst_zone_id', label: 'Dest Zone', type: 'select' as const, options: zoneOptions },
|
||||
{ name: 'src_zone_id', label: 'Source Zone', type: 'select' as const, options: [{ value: '', label: 'all' }, ...zoneOptions] },
|
||||
{ name: 'dst_zone_id', label: 'Dest Zone', type: 'select' as const, options: [{ value: '', label: 'all' }, ...zoneOptions] },
|
||||
{ name: 'src_ip', label: 'Source IP/CIDR' },
|
||||
{ name: 'dst_ip', label: 'Dest IP/CIDR' },
|
||||
{ name: 'proto', label: 'Protocol' },
|
||||
{ name: 'dport', label: 'Dest Port' },
|
||||
{ name: 'sport', label: 'Source Port' },
|
||||
{ name: 'proto', label: 'Protocol', placeholder: 'e.g. tcp, udp, icmp' },
|
||||
{ name: 'dport', label: 'Dest Port(s)' },
|
||||
{ name: 'sport', label: 'Source Port(s)' },
|
||||
{ name: 'origdest', label: 'Original Dest', placeholder: 'e.g. 192.168.1.1' },
|
||||
{ name: 'rate_limit', label: 'Rate Limit', placeholder: 'e.g. 10/sec:20' },
|
||||
{ name: 'user_group', label: 'User/Group', placeholder: 'e.g. joe:wheel' },
|
||||
{ name: 'mark', label: 'Mark', placeholder: 'e.g. 0x100/0xff0' },
|
||||
{ name: 'connlimit', label: 'ConnLimit', placeholder: 'e.g. 10:24' },
|
||||
{ name: 'time', label: 'Time', placeholder: 'e.g. timestart=09:00×top=17:00' },
|
||||
{ name: 'headers', label: 'Headers (IPv6)', placeholder: 'e.g. auth,esp' },
|
||||
{ name: 'switch_name', label: 'Switch', placeholder: 'e.g. vpn_enabled' },
|
||||
{ name: 'helper', label: 'Helper', type: 'select' as const, options: [
|
||||
{ value: '', label: '(none)' },
|
||||
{ value: 'amanda', label: 'amanda' },
|
||||
{ value: 'ftp', label: 'ftp' },
|
||||
{ value: 'irc', label: 'irc' },
|
||||
{ value: 'netbios-ns', label: 'netbios-ns' },
|
||||
{ value: 'pptp', label: 'pptp' },
|
||||
{ value: 'Q.931', label: 'Q.931' },
|
||||
{ value: 'RAS', label: 'RAS' },
|
||||
{ value: 'sane', label: 'sane' },
|
||||
{ value: 'sip', label: 'sip' },
|
||||
{ value: 'snmp', label: 'snmp' },
|
||||
{ value: 'tftp', label: 'tftp' },
|
||||
]},
|
||||
{ name: 'comment', label: 'Comment' },
|
||||
{ name: 'position', label: 'Position', type: 'number' as const },
|
||||
] as FieldDef[],
|
||||
@@ -165,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