From: Otto Moerbeek Date: Thu, 15 Jan 2026 12:12:17 +0000 (+0100) Subject: Encode subnets not a a single path component, but as id/prefixlen as auth does X-Git-Tag: rec-5.4.0-beta1~19^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=446f83c0a276f921be2dad74e67fc3554b3e3201;p=thirdparty%2Fpdns.git Encode subnets not a a single path component, but as id/prefixlen as auth does Signed-off-by: Otto Moerbeek --- diff --git a/pdns/recursordist/docs/http-api/endpoint-ottraceconditions.rst b/pdns/recursordist/docs/http-api/endpoint-ottraceconditions.rst index 88dc842536..3a0f95d03e 100644 --- a/pdns/recursordist/docs/http-api/endpoint-ottraceconditions.rst +++ b/pdns/recursordist/docs/http-api/endpoint-ottraceconditions.rst @@ -17,16 +17,16 @@ OpenTelemetryTraceConditions endpoint :query server_id: The name of the server -.. http:get:: /api/v1/servers/:server_id/ottraceconditions/:subnet +.. http:get:: /api/v1/servers/:server_id/ottraceconditions/:ip/:prefixlen Returns trace condition information. :query server_id: The name of the server - :query subnet: The subnet of the :json:object:`OpenTelemetryTraceCondition`. URL encode subnet, for example ``192.0.2.1/32`` becomes ``192.0.2.1%2F32``. + :query ip/prefixlen: The subnet of the :json:object:`OpenTelemetryTraceCondition`. -.. http:delete:: /api/v1/servers/:server_id/ottraceconditions/:subnet +.. http:delete:: /api/v1/servers/:server_id/ottraceconditions/:ip/:prefixlen Deletes this zone, all attached metadata and rrsets. :query server_id: The name of the server - :query subnet: The subnet of the :json:object:`OpenTelemetryTraceCondition`. URL encode subnet, for example ``192.0.2.1/32`` becomes ``192.0.2.1%2F32``. + :query ip/prefixlen: The subnet of the :json:object:`OpenTelemetryTraceCondition`. diff --git a/pdns/recursordist/rec-rust-lib/rust/src/web.rs b/pdns/recursordist/rec-rust-lib/rust/src/web.rs index e06ffbdb2d..bb6c91b9e0 100644 --- a/pdns/recursordist/rec-rust-lib/rust/src/web.rs +++ b/pdns/recursordist/rec-rust-lib/rust/src/web.rs @@ -402,26 +402,18 @@ fn matcher( (&Method::GET, ["api", "v1", "servers", "localhost", "ottraceconditions"]) => { *apifunc = Some(rustweb::apiServerOTConditionsGET); } - (&Method::GET, ["api", "v1", "servers", "localhost", "ottraceconditions", acl]) => { - let decoded = form_urlencoded::parse(acl.as_bytes()); - // decoded should contain a single key without value - if let Some(kv) = decoded.last() { - request.parameters.push(rustweb::KeyValue { - key: String::from("acl"), - value: kv.0.to_string(), - }); - } + (&Method::GET, ["api", "v1", "servers", "localhost", "ottraceconditions", ip, pflen]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("acl"), + value: String::from(*ip) + "/" + *pflen, + }); *apifunc = Some(rustweb::apiServerOTConditionDetailGET) } - (&Method::DELETE, ["api", "v1", "servers", "localhost", "ottraceconditions", acl]) => { - let decoded = form_urlencoded::parse(acl.as_bytes()); - // decoded should contain a single key without value - if let Some(kv) = decoded.last() { - request.parameters.push(rustweb::KeyValue { - key: String::from("acl"), - value: kv.0.to_string(), - }); - } + (&Method::DELETE, ["api", "v1", "servers", "localhost", "ottraceconditions", ip, pflen]) => { + request.parameters.push(rustweb::KeyValue { + key: String::from("acl"), + value: String::from(*ip) + "/" + *pflen, + }); *apifunc = Some(rustweb::apiServerOTConditionDetailDELETE) } (&Method::POST, ["api", "v1", "servers", "localhost", "ottraceconditions"]) => { diff --git a/regression-tests.api/test_RecursorOTConditions.py b/regression-tests.api/test_RecursorOTConditions.py index c282a3b2ca..091b3ef668 100644 --- a/regression-tests.api/test_RecursorOTConditions.py +++ b/regression-tests.api/test_RecursorOTConditions.py @@ -28,21 +28,21 @@ class RecursorOT(ApiTestCase): # nonexistent condition r = self.session.get( - self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4%2F32"), + self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 422) self.assert_in_json_error('Could not find otcondition', r.json()) # malformed netmask r = self.session.get( - self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3%2F32"), + self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3/32"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 422) self.assert_in_json_error('Could not parse netmask', r.json()) # deleting non-existent netmask r = self.session.delete( - self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4%2F32"), + self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 422) self.assert_in_json_error('Could not find otcondition', r.json()) @@ -108,16 +108,16 @@ class RecursorOT(ApiTestCase): self.assertEqual(r.status_code, 200) self.assertEqual(len(r.json()), 2) - # querying by more specific key + # querying by more specific key than /24 r = self.session.get( - self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4%2F31"), + self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/31"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 422) self.assert_in_json_error('Could not find otcondition', r.json()) # deleting specific netmask r = self.session.delete( - self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4%2F32"), + self.url("/api/v1/servers/localhost/ottraceconditions/1.2.3.4/32"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 204) @@ -160,7 +160,7 @@ class RecursorOT(ApiTestCase): # and GET the newly created one in a separate call r = self.session.get( - self.url("/api/v1/servers/localhost/ottraceconditions/::1%2F0"), + self.url("/api/v1/servers/localhost/ottraceconditions/::/0"), headers={'content-type': 'application/json'}) self.assertEqual(r.status_code, 200) data = r.json()