Skip to content

Commit d2ec24e

Browse files
Merge branch 'master' of github.com:jaredhendrickson13/pfsense-api into next_minor
2 parents 0616184 + 9d2178b commit d2ec24e

File tree

2 files changed

+69
-4
lines changed

2 files changed

+69
-4
lines changed

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Models/PortForward.inc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use RESTAPI\Fields\FilterAddressField;
1111
use RESTAPI\Fields\ForeignModelField;
1212
use RESTAPI\Fields\InterfaceField;
1313
use RESTAPI\Fields\PortField;
14+
use RESTAPI\Fields\SpecialNetworkField;
1415
use RESTAPI\Fields\StringField;
1516
use RESTAPI\Fields\UnixTimeField;
1617
use RESTAPI\Responses\ServerError;
@@ -27,7 +28,7 @@ class PortForward extends Model {
2728
public PortField $source_port;
2829
public FilterAddressField $destination;
2930
public PortField $destination_port;
30-
public StringField $target;
31+
public SpecialNetworkField $target;
3132
public PortField $local_port;
3233
public BooleanField $disabled;
3334
public BooleanField $nordr;
@@ -65,7 +66,7 @@ class PortForward extends Model {
6566
);
6667
$this->protocol = new StringField(
6768
required: true,
68-
choices: ['tcp', 'udp', 'tcp/udp', 'icmp', 'esp', 'ah', 'gre', 'ipv6', 'igmp', 'pim', 'ospf'],
69+
choices: ['any', 'tcp', 'udp', 'tcp/udp', 'icmp', 'esp', 'ah', 'gre', 'ipv6', 'igmp', 'pim', 'ospf'],
6970
help_text: 'The IP/transport protocol this port forward rule should match.',
7071
);
7172
$this->source = new FilterAddressField(
@@ -96,9 +97,17 @@ class PortForward extends Model {
9697
conditions: ['protocol' => ['tcp', 'udp', 'tcp/udp']],
9798
help_text: 'The destination port this port forward rule applies to. Set to `null` to allow any destination port.',
9899
);
99-
$this->target = new StringField(
100+
$this->target = new SpecialNetworkField(
100101
required: true,
101-
validators: [new IPAddressValidator(allow_ipv4: true, allow_ipv6: true, allow_alias: true)],
102+
allow_ipaddr: true,
103+
allow_subnet: false,
104+
allow_alias: true,
105+
allow_interface: false,
106+
allow_interface_ip: true,
107+
allow_interface_groups: false,
108+
allow_self: false,
109+
allow_l2tp: false,
110+
allow_pppoe: false,
102111
help_text: 'The IP address or alias of the internal host to forward matching traffic to.',
103112
);
104113
$this->local_port = new PortField(

pfSense-pkg-RESTAPI/files/usr/local/pkg/RESTAPI/Tests/APIModelsPortForwardTestCase.inc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace RESTAPI\Tests;
44

55
use RESTAPI\Core\TestCase;
6+
use RESTAPI\Models\FirewallAlias;
67
use RESTAPI\Models\FirewallRule;
78
use RESTAPI\Models\PortForward;
9+
use RESTAPI\Responses\ValidationError;
810

911
class APIModelsPortForwardTestCase extends TestCase {
1012
/**
@@ -227,4 +229,58 @@ class APIModelsPortForwardTestCase extends TestCase {
227229
$rule_q = FirewallRule::query(associated_rule_id: $port_forward->associated_rule_id->value);
228230
$this->assert_is_false($rule_q->exists());
229231
}
232+
233+
/**
234+
* Ensures the target field accepts IP addresses, aliases and interface IPs
235+
*/
236+
public function test_target_validation(): void {
237+
# Create an alias to test with
238+
$alias = new FirewallAlias(name: 'testalias', type: 'host');
239+
$alias->create();
240+
241+
# Set values we expect to be allowed vs disallowed
242+
$allowed_values = ['1.2.3.4', 'wan:ip', 'testalias'];
243+
$disallowed_values = ['example.com', 'wan', 'self', 'l2tp', '1.2.3.4/24'];
244+
245+
# Check each allowed value and ensure it does not throw an exception during validation
246+
foreach ($allowed_values as $value) {
247+
$this->assert_does_not_throw(
248+
callable: function () use ($value) {
249+
$port_forward = new PortForward(
250+
data: [
251+
'interface' => 'wan',
252+
'protocol' => 'tcp',
253+
'source' => 'any',
254+
'destination' => 'wan:ip',
255+
'destination_port' => '8443',
256+
'target' => $value,
257+
'local_port' => '4443',
258+
],
259+
);
260+
$port_forward->validate();
261+
},
262+
);
263+
}
264+
265+
# Check each disallowed value and ensure it throws an exception during validation
266+
foreach ($disallowed_values as $value) {
267+
$this->assert_throws(
268+
exceptions: ['RESTAPI\Responses\ValidationError'],
269+
callable: function () use ($value) {
270+
$port_forward = new PortForward(
271+
data: [
272+
'interface' => 'wan',
273+
'protocol' => 'tcp',
274+
'source' => 'any',
275+
'destination' => 'wan:ip',
276+
'destination_port' => '8443',
277+
'target' => $value,
278+
'local_port' => '4443',
279+
],
280+
);
281+
$port_forward->validate();
282+
},
283+
);
284+
}
285+
}
230286
}

0 commit comments

Comments
 (0)