Skip to content

Commit b7c2c5d

Browse files
Added APIFirewallTrafficShaperCreate model to create new traffic shapers for interfaces, added APIFirewallTrafficShaper endpoint to map requests
1 parent 5afa9e9 commit b7c2c5d

3 files changed

Lines changed: 277 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
// Copyright 2021 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIEndpoint.inc");
17+
18+
class APIFirewallTrafficShaper extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/firewall/traffic_shaper";
21+
}
22+
23+
protected function post() {
24+
return (new APIFirewallTrafficShaperCreate())->call();
25+
}
26+
27+
}

pfSense-pkg-API/files/etc/inc/api/framework/APIResponse.inc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,78 @@ function get($id, $data=[], $all=false) {
16401640
"return" => $id,
16411641
"message" => "Firewall rule gateway must match IP protocol"
16421642
],
1643+
4110 => [
1644+
"status" => "bad request",
1645+
"code" => 400,
1646+
"return" => $id,
1647+
"message" => "Firewall traffic shaper interface is required"
1648+
],
1649+
4111 => [
1650+
"status" => "bad request",
1651+
"code" => 400,
1652+
"return" => $id,
1653+
"message" => "Unknown firewall traffic shaper interface"
1654+
],
1655+
4112 => [
1656+
"status" => "bad request",
1657+
"code" => 400,
1658+
"return" => $id,
1659+
"message" => "Firewall traffic shaper already exists for this interface"
1660+
],
1661+
4113 => [
1662+
"status" => "bad request",
1663+
"code" => 400,
1664+
"return" => $id,
1665+
"message" => "Firewall traffic shaper scheduler is required"
1666+
],
1667+
4114 => [
1668+
"status" => "bad request",
1669+
"code" => 400,
1670+
"return" => $id,
1671+
"message" => "Unknown firewall traffic shaper scheduler"
1672+
],
1673+
4115 => [
1674+
"status" => "bad request",
1675+
"code" => 400,
1676+
"return" => $id,
1677+
"message" => "Firewall traffic shaper bandwidth type is required"
1678+
],
1679+
4116 => [
1680+
"status" => "bad request",
1681+
"code" => 400,
1682+
"return" => $id,
1683+
"message" => "Unknown firewall traffic shaper bandwidth type"
1684+
],
1685+
4117 => [
1686+
"status" => "bad request",
1687+
"code" => 400,
1688+
"return" => $id,
1689+
"message" => "Firewall traffic shaper bandwidth is required"
1690+
],
1691+
4118 => [
1692+
"status" => "bad request",
1693+
"code" => 400,
1694+
"return" => $id,
1695+
"message" => "Firewall traffic shaper bandwidth must be 1 or greater"
1696+
],
1697+
4119 => [
1698+
"status" => "bad request",
1699+
"code" => 400,
1700+
"return" => $id,
1701+
"message" => "Firewall traffic shaper bandwidth must be 100 or less with % bandwidth type"
1702+
],
1703+
4120 => [
1704+
"status" => "bad request",
1705+
"code" => 400,
1706+
"return" => $id,
1707+
"message" => "Firewall traffic shaper queue limit must be 1 or greater"
1708+
],
1709+
4121 => [
1710+
"status" => "bad request",
1711+
"code" => 400,
1712+
"return" => $id,
1713+
"message" => "Firewall traffic shaper TBR size must be 1 or greater"
1714+
],
16431715

16441716
//5000-5999 reserved for /users API calls
16451717
5000 => [
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php
2+
// Copyright 2021 Jared Hendrickson
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
require_once("api/framework/APIModel.inc");
17+
require_once("api/framework/APIResponse.inc");
18+
19+
class APIFirewallTrafficShaperCreate extends APIModel {
20+
# Create our method constructor
21+
public function __construct() {
22+
parent::__construct();
23+
$this->privileges = ["page-all", "page-firewall-trafficshaper"];
24+
$this->change_note = "Added firewall traffic shaper via API";
25+
}
26+
27+
public function action() {
28+
# Initialize the traffic shaper configuration and save our shaper, mark the subsystem as un-applied
29+
$this->__init_config();
30+
$this->config["shaper"]["queue"][] = $this->validated_data;
31+
$this->write_config();
32+
mark_subsystem_dirty('shaper');
33+
34+
# Only reload the filter immediately if it was requested by the client
35+
if ($this->initial_data["apply"] === true) {
36+
# Reload the filter, reset RRD logs and mark the subsystem as applied
37+
filter_configure();
38+
system("rm -f /var/db/rrd/*queuedrops.rrd");
39+
system("rm -f /var/db/rrd/*queues.rrd");
40+
enable_rrd_graphing();
41+
clear_subsystem_dirty('shaper');
42+
}
43+
return APIResponse\get(0, $this->validated_data);
44+
}
45+
46+
public function validate_payload() {
47+
$this->__validate_interface();
48+
$this->__validate_scheduler();
49+
$this->__validate_bandwidthtype(); // Must run before __validate_bandwith()
50+
$this->__validate_bandwidth();
51+
$this->__validate_enabled();
52+
$this->__validate_qlimit();
53+
$this->__validate_tbrconfig();
54+
}
55+
56+
private function __validate_interface() {
57+
# Check for our required `interface` payload value
58+
if (isset($this->initial_data["interface"])) {
59+
$this->initial_data["interface"] = APITools\get_pfsense_if_id($this->initial_data["interface"]);
60+
61+
# Check that the requested interface exists
62+
if ($this->initial_data["interface"]) {
63+
# Check that a traffic shaper does not already exist for this interface
64+
if (!$this->get_shaper_id_by_interface($this->initial_data["interface"], true)) {
65+
# Set the interface and name of this shaper
66+
$this->validated_data["interface"] = $this->initial_data["interface"];
67+
$this->validated_data["name"] = $this->initial_data["interface"];
68+
} else {
69+
$this->errors[] = APIResponse\get(4112);
70+
}
71+
} else {
72+
$this->errors[] = APIResponse\get(4111);
73+
}
74+
} else {
75+
$this->errors[] = APIResponse\get(4110);
76+
}
77+
}
78+
79+
private function __validate_scheduler() {
80+
# Check for our required `scheduler` payload value
81+
if (isset($this->initial_data["scheduler"])) {
82+
# Check that the scheduler type is supported
83+
if (in_array($this->initial_data["scheduler"], ["HFSC", "CBQ", "FAIRQ", "CODELQ", "PRIQ"])) {
84+
$this->validated_data["scheduler"] = $this->initial_data["scheduler"];
85+
} else {
86+
$this->errors[] = APIResponse\get(4114);
87+
}
88+
} else {
89+
$this->errors[] = APIResponse\get(4113);
90+
}
91+
}
92+
93+
private function __validate_bandwidthtype() {
94+
# Check for our required `bandwidthtype` payload value
95+
if (isset($this->initial_data["bandwidthtype"])) {
96+
# Check that the scheduler type is supported
97+
if (in_array($this->initial_data["bandwidthtype"], ["%", "b", "Kb", "Mb", "Gb"])) {
98+
$this->validated_data["bandwidthtype"] = $this->initial_data["bandwidthtype"];
99+
} else {
100+
$this->errors[] = APIResponse\get(4116);
101+
}
102+
} else {
103+
$this->errors[] = APIResponse\get(4115);
104+
}
105+
}
106+
107+
private function __validate_bandwidth() {
108+
# Check for our required `bandwidth` payload value
109+
if (isset($this->initial_data["bandwidth"])) {
110+
# Check that the bandwidth is 1 or greater
111+
if (intval($this->initial_data["bandwidth"]) >= 1) {
112+
# If bandwidth type % is used, enforce value to be less than 100
113+
if ($this->validated_data["bandwidthtype"] == "%" and intval($this->initial_data["bandwidth"]) > 100) {
114+
$this->errors[] = APIResponse\get(4119);
115+
} else {
116+
$this->validated_data["bandwidth"] = intval($this->initial_data["bandwidth"]);
117+
}
118+
} else {
119+
$this->errors[] = APIResponse\get(4118);
120+
}
121+
} else {
122+
$this->errors[] = APIResponse\get(4117);
123+
}
124+
}
125+
126+
private function __validate_enabled() {
127+
# Enable this shaper by default if a non-false value was provided
128+
if ($this->initial_data["enabled"] !== false) {
129+
$this->validated_data["enabled"] = "on";
130+
}
131+
}
132+
133+
private function __validate_qlimit() {
134+
# Check for our optional `qlimit` payload value
135+
if (isset($this->initial_data["qlimit"])) {
136+
# Ensure the qlimit is 1 or greater
137+
if (is_numeric($this->initial_data["qlimit"]) and intval($this->initial_data["qlimit"]) >= 1) {
138+
$this->validated_data["qlimit"] = intval($this->initial_data["qlimit"]);
139+
} else {
140+
$this->errors[] = APIResponse\get(4120);
141+
}
142+
}
143+
}
144+
145+
private function __validate_tbrconfig() {
146+
# Check for our optional `tbrconfig` payload value
147+
if (isset($this->initial_data["tbrconfig"])) {
148+
# Ensure the tbrconfig is 1 or greater
149+
if (is_numeric($this->initial_data["tbrconfig"]) and intval($this->initial_data["tbrconfig"]) >= 1) {
150+
$this->validated_data["tbrconfig"] = intval($this->initial_data["tbrconfig"]);
151+
} else {
152+
$this->errors[] = APIResponse\get(4121);
153+
}
154+
}
155+
}
156+
157+
private function __init_config() {
158+
# Check if there is no shaper array in the config
159+
if (empty($this->config["shaper"])) {
160+
$this->config["shaper"] = [];
161+
}
162+
# Check if there is no shaper queue array in the config
163+
if (empty($this->config["shaper"]["queue"])) {
164+
$this->config["shaper"]["queue"] = [];
165+
}
166+
}
167+
168+
public function get_shaper_id_by_interface($interface, $as_bool=false) {
169+
# Loop through each configured shaper
170+
foreach ($this->config["shaper"]["queue"] as $id=>$shaper) {
171+
# Check if this is the shaper for our interface, if so return it's ID
172+
if ($interface === $shaper["interface"]) {
173+
return ($as_bool) ? true : intval($id);
174+
}
175+
}
176+
return ($as_bool) ? false : null;
177+
}
178+
}

0 commit comments

Comments
 (0)