Skip to content

Commit 203d056

Browse files
author
Jared Hendrickson
committed
Created endpoint for reading and updating outbound NAT mode, create unit test for outbound NAT endpoint, updated docs
1 parent a0f2216 commit 203d056

8 files changed

Lines changed: 401 additions & 2 deletions

File tree

README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,11 @@ There is no limit to API calls at this time but is important to note that pfSens
515515
* [Read NAT 1:1 Mappings](#3-read-nat-1:1-mappings)
516516
* [Update NAT 1:1 Mappings](#4-update-nat-1:1-mappings)
517517

518+
* [FIREWALL/NAT/OUTBOUND](#firewallnatoutbound)
519+
520+
* [Read Outbound NAT Settings](#1-read-outbound-nat-settings)
521+
* [Update Outbound NAT Settings](#2-update-outbound-nat-settings)
522+
518523
* [FIREWALL/NAT/PORTFOWARD](#firewallnatportfoward)
519524

520525
* [Create NAT Port Forwards](#1-create-nat-port-forwards)
@@ -1204,6 +1209,74 @@ URL: https://{{$hostname}}/api/v1/firewall/nat/port_forward
12041209

12051210

12061211

1212+
## FIREWALL/NAT/OUTBOUND
1213+
1214+
1215+
1216+
### 1. Read Outbound NAT Settings
1217+
1218+
1219+
Read outbound NAT mode settings.<br><br>
1220+
1221+
_Requires at least one of the following privileges:_ [`page-all`, `page-firewall-nat-outbound`]
1222+
1223+
1224+
***Endpoint:***
1225+
1226+
```bash
1227+
Method: GET
1228+
Type: RAW
1229+
URL: https://{{$hostname}}/api/v1/firewall/nat/outbound
1230+
```
1231+
1232+
1233+
1234+
***Body:***
1235+
1236+
```js
1237+
{
1238+
1239+
}
1240+
```
1241+
1242+
1243+
1244+
### 2. Update Outbound NAT Settings
1245+
1246+
1247+
Update outbound NAT mode settings.<br><br>
1248+
1249+
_Requires at least one of the following privileges:_ [`page-all`, `page-firewall-nat-outbound`]
1250+
1251+
1252+
***Endpoint:***
1253+
1254+
```bash
1255+
Method: PUT
1256+
Type: RAW
1257+
URL: https://{{$hostname}}/api/v1/firewall/nat/outbound
1258+
```
1259+
1260+
1261+
1262+
***Query params:***
1263+
1264+
| Key | Value | Description |
1265+
| --- | ------|-------------|
1266+
| mode | string | Update the outbound NAT mode. Options are `automatic` to automatically generate outbound NAT rules, `hybrid` to support both automatiic and manual outbound NAT rules , `advanced` to require all rules to be entered manually, or `disabled` to disable outbound NAT altogether. If updating to `advanced` from `automatic` or `hybrid`, the API will automatically create manual entries for each automatically generated outbound NAT entry. |
1267+
1268+
1269+
1270+
***Body:***
1271+
1272+
```js
1273+
{
1274+
1275+
}
1276+
```
1277+
1278+
1279+
12071280
## FIREWALL/NAT/PORTFOWARD
12081281

12091282

docs/documentation.json

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3220,6 +3220,110 @@
32203220
}
32213221
],
32223222
"description": "API endpoints that create, read, update and delete 1:1 NAT mappings.",
3223+
"event": [
3224+
{
3225+
"listen": "prerequest",
3226+
"script": {
3227+
"id": "b651d13f-bac6-4972-b51b-e809a66de831",
3228+
"type": "text/javascript",
3229+
"exec": [
3230+
""
3231+
]
3232+
}
3233+
},
3234+
{
3235+
"listen": "test",
3236+
"script": {
3237+
"id": "e47f7092-4987-458a-9712-e6073c33a4f7",
3238+
"type": "text/javascript",
3239+
"exec": [
3240+
""
3241+
]
3242+
}
3243+
}
3244+
],
3245+
"protocolProfileBehavior": {},
3246+
"_postman_isSubFolder": true
3247+
},
3248+
{
3249+
"name": "OUTBOUND",
3250+
"item": [
3251+
{
3252+
"name": "Read Outbound NAT Settings",
3253+
"protocolProfileBehavior": {
3254+
"disableBodyPruning": true
3255+
},
3256+
"request": {
3257+
"method": "GET",
3258+
"header": [],
3259+
"body": {
3260+
"mode": "raw",
3261+
"raw": "{\n \n}",
3262+
"options": {
3263+
"raw": {
3264+
"language": "json"
3265+
}
3266+
}
3267+
},
3268+
"url": {
3269+
"raw": "https://{{$hostname}}/api/v1/firewall/nat/outbound",
3270+
"protocol": "https",
3271+
"host": [
3272+
"{{$hostname}}"
3273+
],
3274+
"path": [
3275+
"api",
3276+
"v1",
3277+
"firewall",
3278+
"nat",
3279+
"outbound"
3280+
]
3281+
},
3282+
"description": "Read outbound NAT mode settings.<br><br>\n\n_Requires at least one of the following privileges:_ [`page-all`, `page-firewall-nat-outbound`]"
3283+
},
3284+
"response": []
3285+
},
3286+
{
3287+
"name": "Update Outbound NAT Settings",
3288+
"request": {
3289+
"method": "PUT",
3290+
"header": [],
3291+
"body": {
3292+
"mode": "raw",
3293+
"raw": "{\n \n}",
3294+
"options": {
3295+
"raw": {
3296+
"language": "json"
3297+
}
3298+
}
3299+
},
3300+
"url": {
3301+
"raw": "https://{{$hostname}}/api/v1/firewall/nat/outbound?mode=string",
3302+
"protocol": "https",
3303+
"host": [
3304+
"{{$hostname}}"
3305+
],
3306+
"path": [
3307+
"api",
3308+
"v1",
3309+
"firewall",
3310+
"nat",
3311+
"outbound"
3312+
],
3313+
"query": [
3314+
{
3315+
"key": "mode",
3316+
"value": "string",
3317+
"description": "Update the outbound NAT mode. Options are `automatic` to automatically generate outbound NAT rules, `hybrid` to support both automatiic and manual outbound NAT rules , `advanced` to require all rules to be entered manually, or `disabled` to disable outbound NAT altogether. If updating to `advanced` from `automatic` or `hybrid`, the API will automatically create manual entries for each automatically generated outbound NAT entry."
3318+
}
3319+
]
3320+
},
3321+
"description": "Update outbound NAT mode settings.<br><br>\n\n_Requires at least one of the following privileges:_ [`page-all`, `page-firewall-nat-outbound`]"
3322+
},
3323+
"response": []
3324+
}
3325+
],
3326+
"description": "API endpoints that create, read, update and delete outbound NAT settings.",
32233327
"protocolProfileBehavior": {},
32243328
"_postman_isSubFolder": true
32253329
},
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
// Copyright 2020 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 APIFirewallNATOutbound extends APIEndpoint {
19+
public function __construct() {
20+
$this->url = "/api/v1/firewall/nat/outbound";
21+
}
22+
23+
protected function get() {
24+
return (new APIFirewallNATOutboundRead())->call();
25+
}
26+
27+
protected function put() {
28+
return (new APIFirewallNATOutboundUpdate())->call();
29+
}
30+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,6 +1394,12 @@ function get($id, $data=[], $all=false) {
13941394
"return" => $id,
13951395
"message" => "1:1 NAT rule ID does not exist"
13961396
],
1397+
4085 => [
1398+
"status" => "bad request",
1399+
"code" => 400,
1400+
"return" => $id,
1401+
"message" => "Invalid outbound NAT mode"
1402+
],
13971403

13981404
//5000-5999 reserved for /users API calls
13991405
5000 => [
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
// Copyright 2020 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 APIFirewallNATOutboundRead extends APIModel {
20+
# Create our method constructor
21+
public function __construct() {
22+
parent::__construct();
23+
$this->privileges = ["page-all", "page-firewall-nat-outbound"];
24+
}
25+
26+
public function action() {
27+
# If default outbound NAT mode (auto) is configured, set a representation of this value since none is shown
28+
if (empty($this->config["nat"]["outbound"]["mode"])) {
29+
$this->validated_data = ["mode" => "automatic"];
30+
} else {
31+
$this->validated_data = ["mode" => $this->config["nat"]["outbound"]["mode"]];
32+
}
33+
return APIResponse\get(0, $this->validated_data);
34+
}
35+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
// Copyright 2020 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 APIFirewallNATOutboundUpdate extends APIModel {
20+
private $modes;
21+
private $current_mode;
22+
23+
# Create our method constructor
24+
public function __construct() {
25+
parent::__construct();
26+
$this->privileges = ["page-all", "page-firewall-nat-outbound"];
27+
$this->modes = ["automatic", "hybrid", "advanced", "disabled"];
28+
29+
}
30+
31+
public function action() {
32+
# Create automatic rules if required, write to config and reload the filter
33+
$this->create_automatic_rules();
34+
$this->config["nat"]["outbound"]["mode"] = $this->validated_data["mode"];
35+
$this->write_config();
36+
filter_configure();
37+
38+
return APIResponse\get(0, $this->validated_data);
39+
}
40+
41+
private function __get_default() {
42+
# Default to the current configured value, if no value is configured default to automatic
43+
$this->validated_data["mode"] = $this->config["nat"]["outbound"]["mode"];
44+
if (empty($this->validated_data["mode"])) {
45+
$this->validated_data["mode"] = "automatic";
46+
}
47+
}
48+
49+
private function __validate_mode() {
50+
$this->current_mode = $this->validated_data["mode"];
51+
# Optionally allow client to update the outbound NAT mode
52+
if (isset($this->initial_data["mode"])) {
53+
# Require the mode to be a supported outbound NAT mode
54+
if (in_array($this->initial_data["mode"], $this->modes)) {
55+
$this->validated_data["mode"] = $this->initial_data["mode"];
56+
} else {
57+
$this->errors[] = APIResponse\get(4085);
58+
}
59+
}
60+
}
61+
62+
# Creates manual rule entries for auto created rules when switching from hybrid/automatic to advanced
63+
public function create_automatic_rules() {
64+
global $FilterIflist;
65+
global $GatewaysList;
66+
67+
if ($this->validated_data["mode"] == "advanced" and in_array($this->current_mode, ["automatic", "hybrid"])) {
68+
if (empty($FilterIflist)) {
69+
filter_generate_optcfg_array();
70+
}
71+
72+
if (empty($GatewaysList)) {
73+
filter_generate_gateways();
74+
}
75+
$to_nat_hosts = filter_nat_rules_automatic_tonathosts(true);
76+
$automatic_rules = filter_nat_rules_outbound_automatic("");
77+
78+
foreach ($to_nat_hosts as $to_nat_host) {
79+
foreach ($automatic_rules as $nat_ent) {
80+
$nat_ent['source']['network'] = $to_nat_host['subnet'];
81+
$nat_ent['descr'] .= sprintf(gettext(' - %1$s to %2$s'),
82+
$to_nat_host['descr'],
83+
convert_real_interface_to_friendly_descr($nat_ent['interface']));
84+
$nat_ent['created'] = make_config_revision_entry(null, gettext("Manual Outbound NAT Switch"));
85+
86+
if ($this->__is_duplicate_rule($nat_ent) === false) {
87+
$this->config["nat"]["outbound"]["rule"][] = $nat_ent;
88+
}
89+
}
90+
}
91+
unset($FilterIflist, $GatewaysList);
92+
}
93+
}
94+
95+
# Checks if this outbound NAT entry is a duplicate. Returns true or false.
96+
private function __is_duplicate_rule($nat_ent) {
97+
foreach ($this->config["nat"]["outbound"]["rule"] as $rule) {
98+
if ($rule['interface'] == $nat_ent['interface'] &&
99+
$rule['source']['network'] == $nat_ent['source']['network'] &&
100+
$rule['dstport'] == $nat_ent['dstport'] &&
101+
$rule['target'] == $nat_ent['target'] &&
102+
$rule['descr'] == $nat_ent['descr']) {
103+
return true;
104+
}
105+
}
106+
return false;
107+
}
108+
109+
public function validate_payload() {
110+
$this->__get_default();
111+
$this->__validate_mode();
112+
}
113+
}

pfSense-pkg-API/files/usr/local/www/api/documentation/index.php

Lines changed: 13 additions & 2 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)