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