From 7e4600b5a12052236869938c4b7dcedb5349b717 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Mon, 13 Jul 2026 15:04:55 +0800 Subject: [PATCH] fix(marker): validate marker name and expose enabled via REST Add a name pattern constraint to MarkerCreate schema (alphanumeric + _.-) to prevent injection into uBridge commands, with a matching defense-in-depth check in _ubridge_add_marker_filter for hand-edited topology files. Also add the missing "enabled" field to MarkerCreate and pass it through the PUT route so the documented toggle actually works. --- gns3server/api/routes/controller/links.py | 1 + gns3server/compute/base_node.py | 5 +++++ gns3server/schemas/controller/links.py | 13 +++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/gns3server/api/routes/controller/links.py b/gns3server/api/routes/controller/links.py index b48d490f1..12ef9eeff 100644 --- a/gns3server/api/routes/controller/links.py +++ b/gns3server/api/routes/controller/links.py @@ -506,6 +506,7 @@ async def update_marker( bpf=marker_data.bpf if marker_data.bpf else None, tag=marker_data.tag, color=marker_data.color, + enabled=marker_data.enabled, ) return link.markers.get(marker_name, {}) diff --git a/gns3server/compute/base_node.py b/gns3server/compute/base_node.py index 8ce6c6783..4b6deff10 100644 --- a/gns3server/compute/base_node.py +++ b/gns3server/compute/base_node.py @@ -1091,6 +1091,11 @@ class BaseNode: """ # mark [tag ] [pcap ] — tag/pcap keyword pairs, any order. + # name travels from the controller REST layer (MarkerCreate schema) but is + # validated here too as defense-in-depth against hand-edited topology files. + _MARKER_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.-]*$") + if not _MARKER_NAME_RE.match(name): + raise UbridgeError(f"Invalid marker name: {name!r}") cmd = 'bridge add_packet_filter {bridge} {name} mark "{bpf}"'.format( bridge=bridge_name, name=name, bpf=bpf ) diff --git a/gns3server/schemas/controller/links.py b/gns3server/schemas/controller/links.py index a05c8187c..2deae4fb2 100644 --- a/gns3server/schemas/controller/links.py +++ b/gns3server/schemas/controller/links.py @@ -149,13 +149,22 @@ class MarkerCreate(BaseModel): absent) but always set when the controller forwards to the compute. """ - name: Optional[str] = None + name: Optional[str] = Field( + None, + pattern=r"^[A-Za-z0-9][A-Za-z0-9_.-]*$", + max_length=128, + description="Unique marker name on the link. Auto-generated when absent.", + ) bpf: str tag: Optional[int] = None link_id: Optional[str] = None color: Optional[str] = Field( None, - description="User-chosen hex color for this marker in the Web UI, e.g. '#ff5722'" + description="User-chosen hex color for this marker in the Web UI, e.g. '#ff5722'", + ) + enabled: Optional[bool] = Field( + None, + description="Whether the marker is active. Defaults to true on creation.", )