1+ <?php
2+ require_once ("api/framework/APIBaseModel.inc " );
3+ require_once ("api/framework/APIResponse.inc " );
4+
5+ class APIFirewallRulesAdd extends APIBaseModel {
6+ # Create our method constructor
7+ public function __construct () {
8+ parent ::__construct ();
9+ $ this ->methods = ["POST " ];
10+ $ this ->privileges = ["page-all " , "page-firewall-rules-edit " ];
11+ }
12+
13+ public function action () {
14+ global $ config ;
15+ $ next_rule_id = count ($ config ["filter " ]["rule " ]); // Save our next rule ID
16+ $ _SESSION ["Username " ] = $ this ->client ->username ; // Save our CLIENT ID to session data for logging
17+ $ change_note = " Added firewall rule via API " ; // Add a change note
18+ $ config ["filter " ]["rule " ][] = $ this ->validated_data ; // Write to our master config
19+ APITools \sort_firewall_rules ($ this ->initial_data ["top " ], $ next_rule_id ); // Sort our firewall rules
20+ write_config (sprintf (gettext ($ change_note ))); // Apply our configuration change
21+ send_event ("filter reload " ); // Ensure our firewall filter is reloaded
22+ return APIResponse \get (0 , $ this ->validated_data );
23+ }
24+
25+ // TODO: break this down into smaller field specific validators
26+ public function validate_payload () {
27+ global $ config ;
28+ $ user_created_msg = $ this ->client ->username ."@ " .$ this ->client ->ip_address ." (API) " ;
29+ $ allowed_rule_types = array ("pass " , "block " , "reject " ); // Array of allowed rule types
30+ $ allowed_ip_prot = array ("inet " , "inet6 " , "inet46 " ); // Array of allowed IP protocols
31+ $ allowed_prot = array (
32+ "any " ,
33+ "tcp " ,
34+ "udp " ,
35+ "tcp/udp " ,
36+ "icmp " ,
37+ "esp " ,
38+ "ah " ,
39+ "gre " ,
40+ "ipv6 " ,
41+ "igmp " ,
42+ "pim " ,
43+ "ospf " ,
44+ "carp " ,
45+ "pfsync "
46+ );
47+ // Array of allowed ICMP subtypes
48+ $ icmp_subtypes = array (
49+ "althost " ,
50+ "dataconv " ,
51+ "echorep " ,
52+ "echoreq " ,
53+ "inforep " ,
54+ "inforeq " ,
55+ "ipv6-here " ,
56+ "ipv6-where " ,
57+ "maskrep " ,
58+ "maskreq " ,
59+ "mobredir " ,
60+ "mobregrep " ,
61+ "mobregreq " ,
62+ "paramprob " ,
63+ "photuris " ,
64+ "redir " ,
65+ "routeradv " ,
66+ "routersol " ,
67+ "skip " ,
68+ "squench " ,
69+ "timerep " ,
70+ "timereq " ,
71+ "timex " ,
72+ "trace " ,
73+ "unreach "
74+ );
75+ if (isset ($ this ->initial_data ['type ' ])) {
76+ $ type = $ this ->initial_data ['type ' ];
77+ } else {
78+ $ this ->errors [] = APIResponse \get (4033 );
79+ }
80+ if (isset ($ this ->initial_data ['interface ' ])) {
81+ $ interface = $ this ->initial_data ['interface ' ];
82+ $ interface = APITools \get_pfsense_if_id ($ interface );
83+ } else {
84+ $ this ->errors [] = APIResponse \get (4034 );
85+
86+ }
87+ if (isset ($ this ->initial_data ['ipprotocol ' ])) {
88+ $ ipprotocol = $ this ->initial_data ['ipprotocol ' ];
89+ } else {
90+ $ this ->errors [] = APIResponse \get (4035 );
91+ }
92+ if (isset ($ this ->initial_data ['protocol ' ])) {
93+ $ protocol = $ this ->initial_data ['protocol ' ];
94+ } else {
95+ $ this ->errors [] = APIResponse \get (4036 );
96+ }
97+ if (isset ($ this ->initial_data ['src ' ])) {
98+ $ src = $ this ->initial_data ['src ' ];
99+ } else {
100+ $ this ->errors [] = APIResponse \get (4037 );
101+ }
102+ if (isset ($ this ->initial_data ['srcport ' ])) {
103+ $ srcport = $ this ->initial_data ['srcport ' ];
104+ }
105+ if (isset ($ this ->initial_data ['dst ' ])) {
106+ $ dst = $ this ->initial_data ['dst ' ];
107+ } else {
108+ $ this ->errors [] = APIResponse \get (4038 );
109+ }
110+ if (isset ($ this ->initial_data ['dstport ' ])) {
111+ $ dstport = $ this ->initial_data ['dstport ' ];
112+ }
113+ if (isset ($ this ->initial_data ['icmptype ' ])) {
114+ $ icmp_type = $ this ->initial_data ['icmptype ' ];
115+ if (!is_array ($ icmp_type )) {
116+ $ icmp_type = array ($ icmp_type );
117+ }
118+ }
119+ if (isset ($ this ->initial_data ['gateway ' ])) {
120+ $ gateway = $ this ->initial_data ['gateway ' ];
121+ }
122+ if (isset ($ this ->initial_data ['disabled ' ])) {
123+ $ disabled = true ;
124+ }
125+ if (isset ($ this ->initial_data ['descr ' ])) {
126+ $ descr = $ this ->initial_data ['descr ' ];
127+ }
128+ if (isset ($ this ->initial_data ['log ' ])) {
129+ $ log = true ;
130+ }
131+ if (isset ($ this ->initial_data ['top ' ])) {
132+ $ this ->initial_data ['top ' ] = "top " ;
133+ }
134+ // INPUT VALIDATION/FORMATTING
135+ // Check that our required array/interface values are valid
136+ if (!in_array ($ type , $ allowed_rule_types )) {
137+ $ this ->errors [] = APIResponse \get (4039 );
138+ } elseif (!is_string ($ interface )) {
139+ $ this ->errors [] = APIResponse \get (4040 );
140+ } elseif (!in_array ($ ipprotocol , $ allowed_ip_prot )) {
141+ $ this ->errors [] = APIResponse \get (4041 );
142+ } elseif (!in_array ($ protocol , $ allowed_prot )) {
143+ $ this ->errors [] = APIResponse \get (4042 );
144+ } elseif (isset ($ gateway ) and !APITools \is_gateway ($ gateway )) {
145+ $ this ->errors [] = APIResponse \get (4043 );
146+ }
147+ // Check if rule is not disabled
148+ if (!$ disabled ) {
149+ $ this ->validated_data ["id " ] = "" ;
150+ }
151+ // Check if logging is enabled
152+ if ($ log ) {
153+ $ this ->validated_data ["log " ] = "" ;
154+ }
155+ // Check if gateway was specified
156+ if (isset ($ gateway )) {
157+ $ this ->validated_data ["gateway " ] = $ gateway ;
158+ }
159+ $ this ->validated_data ["type " ] = $ type ;
160+ $ this ->validated_data ["interface " ] = $ interface ;
161+ $ this ->validated_data ["ipprotocol " ] = $ ipprotocol ;
162+ $ this ->validated_data ["source " ] = array ();
163+ $ this ->validated_data ["destination " ] = array ();
164+ $ this ->validated_data ["descr " ] = $ descr ;
165+ $ this ->validated_data ["created " ] = array ("time " => time (), "username " => $ user_created_msg );
166+ $ this ->validated_data ["updated " ] = $ this ->validated_data ["created " ];
167+ // Save our protocol if it is not 'any'
168+ if ($ protocol !== "any " ) {
169+ $ this ->validated_data ["protocol " ] = $ protocol ;
170+ }
171+ // Add logging to config if enabled
172+ if ($ log ) {
173+ $ this ->validated_data ["log " ] = "" ;
174+ }
175+ // Check if our source and destination values are valid
176+ foreach (array ("source " => $ src , "destination " => $ dst ) as $ dir => $ val ) {
177+ $ dir_check = APITools \is_valid_rule_addr ($ val , $ dir );
178+ if (!$ dir_check ["valid " ] === true ) {
179+ $ input_err = true ;
180+ if ($ dir === "source " ) {
181+ $ this ->errors [] = APIResponse \get (4044 );
182+ } else {
183+ $ this ->errors [] = APIResponse \get (4045 );
184+ }
185+ } else {
186+ $ this ->validated_data = array_merge ($ this ->validated_data , $ dir_check ["data " ]);
187+ }
188+ }
189+ // Check if protocol calls for additional specifications
190+ if (in_array ($ protocol , array ("tcp " , "udp " , "tcp/udp " ))) {
191+ $ port_req = true ;
192+ } elseif ($ protocol === "icmp " ) {
193+ // Check if user specified ICMP subtypes
194+ if (is_array ($ icmp_type )) {
195+ // Loop through each of our subtypes
196+ foreach ($ icmp_type as $ ict ) {
197+ if (!in_array ($ ict , $ icmp_subtypes )) {
198+ $ this ->errors [] = APIResponse \get (4046 );
199+ }
200+ }
201+ // Write our ICMP subtype config
202+ $ this ->validated_data ["icmptype " ] = implode (", " , $ icmp_type );
203+ }
204+ }
205+ // Check our src and dst port values if ports are required
206+ if ($ port_req ) {
207+ if (!isset ($ srcport ) or !isset ($ dstport )) {
208+ $ this ->errors [] = APIResponse \get (4047 );
209+
210+ }
211+ foreach (array ("source " => $ srcport , "destination " => $ dstport ) as $ dir => $ val ) {
212+ $ val = str_replace ("- " , ": " , $ val );
213+ if (!is_port_or_range ($ val ) and $ val !== "any " ) {
214+ $ input_err = true ;
215+ if ($ dir === "source " ) {
216+ $ this ->errors [] = APIResponse \get (4048 );
217+
218+ } else {
219+ $ this ->errors [] = APIResponse \get (4049 );
220+ }
221+ } elseif ($ val !== "any " ) {
222+ $ this ->validated_data [$ dir ]["port " ] = str_replace (": " , "- " , $ val );;
223+ }
224+ }
225+ }
226+ }
227+ }
0 commit comments