From be42b09309b98a660dc435d1ea59a60200bb66b3 Mon Sep 17 00:00:00 2001 From: wuarmin <armin@wurzweb.com> Date: Wed, 25 May 2022 14:23:41 +0200 Subject: [PATCH 1/3] Added /api/v1/services/wol/send/ endpoint to be able to send a WOL packet to a host --- .../inc/api/endpoints/APIServicesWOLSend.inc | 26 +++++++ .../etc/inc/api/framework/APIResponse.inc | 30 ++++++++ .../api/models/APIServicesWOLSendCreate.inc | 76 +++++++++++++++++++ .../local/www/api/documentation/openapi.yml | 29 +++++++ tests/test_api_v1_services_wol_send.py | 63 +++++++++++++++ 5 files changed, 224 insertions(+) create mode 100644 pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesWOLSend.inc create mode 100644 pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc create mode 100644 tests/test_api_v1_services_wol_send.py diff --git a/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesWOLSend.inc b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesWOLSend.inc new file mode 100644 index 000000000..ae0201426 --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/endpoints/APIServicesWOLSend.inc @@ -0,0 +1,26 @@ +<?php +// Copyright 2022 Jared Hendrickson +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +require_once("api/framework/APIEndpoint.inc"); + +class APIServicesWOLSend extends APIEndpoint { + public function __construct() { + $this->url = "/api/v1/services/wol/send"; + } + + protected function post() { + return (new APIServicesWOLSendCreate())->call(); + } +} diff --git a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc index eb5beb19c..532285b50 100644 --- a/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc +++ b/pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc @@ -1193,6 +1193,36 @@ function get($id, $data=[], $all=false) { "return" => $id, "message" => "Host overrides must be contained within an array" ], + 2099 => [ + "status" => "bad request", + "code" => 400, + "return" => $id, + "message" => "No interface specified" + ], + 2100 => [ + "status" => "bad request", + "code" => 400, + "return" => $id, + "message" => "Could not obtain IP address for interface" + ], + 2101 => [ + "status" => "bad request", + "code" => 400, + "return" => $id, + "message" => "No MAC address specified" + ], + 2102 => [ + "status" => "bad request", + "code" => 400, + "return" => $id, + "message" => "Invalid MAC address specified" + ], + 2103 => [ + "status" => "server error", + "code" => 500, + "return" => $id, + "message" => "Please check the system_logs, the WOL command did not complete successfully" + ], 2999 => [ "status" => "bad request", "code" => 400, diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc new file mode 100644 index 000000000..a94636d6a --- /dev/null +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc @@ -0,0 +1,76 @@ +<?php +// Copyright 2022 Jared Hendrickson +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +require_once("api/framework/APIModel.inc"); +require_once("api/framework/APIResponse.inc"); + +class APIServicesWOLSendCreate extends APIModel { + # Create our method constructor + public function __construct() { + parent::__construct(); + $this->privileges = ["page-all", "page-services-wakeonlan"]; + $this->change_note = "Sent magic WOL packet via API"; + } + + public function action() { + $if = $this->validated_data["interface"]; + $if_ip = $this->validated_data["interface_ip"]; + $mac = $this->validated_data["mac"]; + + $bc_ip = $this->__get_broadcast_ip($if, $if_ip); + $response_data = array_merge($this->validated_data, ["broadcast_ip" => $bc_ip]); + + if (!mwexec("/usr/local/bin/wol -i {$bc_ip} {$mac}")) { + return APIResponse\get(0, $response_data); + } else { + return APIResponse\get(2103, $response_data); + } + } + + private function __get_broadcast_ip($if, $if_ip) { + return gen_subnet_max($if_ip, get_interface_subnet($if)); + } + + public function validate_payload() { + $this->__validate_interface(); + $this->__validate_mac(); + } + + private function __validate_interface() { + if (isset($this->initial_data["interface"])) { + $interface_ip = get_interface_ip($this->initial_data["interface"]); + if (is_ipaddr($interface_ip)) { + $this->validated_data["interface"] = $this->initial_data["interface"]; + $this->validated_data["interface_ip"] = $interface_ip; + } else { + $this->errors[] = APIResponse\get(2100, ["interface" => $this->initial_data["interface"], "interface_ip" => $interface_ip]); + } + } else { + $this->errors[] = APIResponse\get(2099); + } + } + + private function __validate_mac() { + if (isset($this->initial_data["mac"])) { + if (is_macaddr($this->initial_data["mac"])) { + $this->validated_data["mac"] = $this->initial_data["mac"]; + } else { + $this->errors[] = APIResponse\get(2102); + } + } else { + $this->errors[] = APIResponse\get(2101); + } + } +} diff --git a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml index 086e1505b..0c1c11cdc 100644 --- a/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml +++ b/pfSense-pkg-API/files/usr/local/www/api/documentation/openapi.yml @@ -7500,6 +7500,34 @@ paths: summary: Stop DNS Resolver (Unbound) service tags: - Services > Unbound + /api/v1/services/wol/send: + post: + description: 'Send a magic WOL packet to a host.<br><br> + + _Requires at least one of the following privileges:_ [`page-all`, `page-services-wakeonlan`]' + requestBody: + content: + application/json: + schema: + properties: + interface: + description: Interface to which the host to be woken is connected. + type: string + mac: + description: MAC address of the host to be woken. + type: string + required: + - interface + - mac + type: object + responses: + 200: + $ref: '#/components/responses/Success' + 401: + $ref: '#/components/responses/AuthenticationFailed' + summary: Send a magic WOL packet to a host + tags: + - Services > WOL /api/v1/status/carp: get: description: 'Read the CARP (failover) status.<br><br> @@ -9580,5 +9608,6 @@ tags: - name: Services > SSHD - name: Services > SYSLOGD - name: Services > DDNS + - name: Services > WOL - name: Diagnostics > Command Prompt diff --git a/tests/test_api_v1_services_wol_send.py b/tests/test_api_v1_services_wol_send.py new file mode 100644 index 000000000..1848cb62a --- /dev/null +++ b/tests/test_api_v1_services_wol_send.py @@ -0,0 +1,63 @@ +# Copyright 2022 Jared Hendrickson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import e2e_test_framework + +class APIE2ETestServicesWOLSend(e2e_test_framework.APIE2ETest): + uri = "/api/v1/services/wol/send/" + post_tests = [ + { + "name": "Send magic WOL packet", + "payload": { + "interface": "lan", + "mac": "2C:54:91:88:C9:E3" + } + }, + { + "name": "Send magic WOL packet with missing interface", + "payload": { + "mac": "2C:54:91:88:C9:E3", + }, + "status": 400, + "return": 2099 + }, + { + "name": "Send magic WOL packet with invalid interface", + "payload": { + "interface": "INVALID", + "mac": "2C:54:91:88:C9:E3" + }, + "status": 400, + "return": 2100 + }, + { + "name": "Send magic WOL packet with missing mac", + "payload": { + "interface": "lan" + }, + "status": 400, + "return": 2101 + }, + { + "name": "Send magic WOL packet with invalid mac", + "payload": { + "interface": "lan", + "mac": "INVALID" + }, + "status": 400, + "return": 2102 + }, + ] + +APIE2ETestServicesWOLSend() From dc1db2d55eb208bf2625c2189f3bd1f2d7eebd50 Mon Sep 17 00:00:00 2001 From: wuarmin <armin@wurzweb.com> Date: Wed, 25 May 2022 20:20:18 +0200 Subject: [PATCH 2/3] Removed unnecessary response data from Error-APIResponse --- .../files/etc/inc/api/models/APIServicesWOLSendCreate.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc index a94636d6a..11c7e4683 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc @@ -55,7 +55,7 @@ class APIServicesWOLSendCreate extends APIModel { $this->validated_data["interface"] = $this->initial_data["interface"]; $this->validated_data["interface_ip"] = $interface_ip; } else { - $this->errors[] = APIResponse\get(2100, ["interface" => $this->initial_data["interface"], "interface_ip" => $interface_ip]); + $this->errors[] = APIResponse\get(2100); } } else { $this->errors[] = APIResponse\get(2099); From 88b311d51405ae8745c314a2e56e03fead5e2309 Mon Sep 17 00:00:00 2001 From: wuarmin <armin@wurzweb.com> Date: Mon, 30 May 2022 09:39:06 +0200 Subject: [PATCH 3/3] Improved interface lookup at /api/v1/services/wol/send-endpoint --- .../files/etc/inc/api/models/APIServicesWOLSendCreate.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc index 11c7e4683..79686f309 100644 --- a/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc +++ b/pfSense-pkg-API/files/etc/inc/api/models/APIServicesWOLSendCreate.inc @@ -50,9 +50,10 @@ class APIServicesWOLSendCreate extends APIModel { private function __validate_interface() { if (isset($this->initial_data["interface"])) { - $interface_ip = get_interface_ip($this->initial_data["interface"]); + $interface = APITools\get_pfsense_if_id($this->initial_data['interface']); + $interface_ip = get_interface_ip($interface); if (is_ipaddr($interface_ip)) { - $this->validated_data["interface"] = $this->initial_data["interface"]; + $this->validated_data["interface"] = $interface; $this->validated_data["interface_ip"] = $interface_ip; } else { $this->errors[] = APIResponse\get(2100);