IC2 API to create firewall rulesets that reference grouped networks - how?

So I have been working with the IC2 API for a few years now, and done a lot of empirical testing.

Honestly, the documentation is sometimes a bit lacking. For calls that take data, sometimes the data requested isn’t shown, and you basically have to manually create what you want via IC2 then query the API, and use those results as a template. This is something I have been doing since the beginning of hammering on the API.

Additionally, sometimes there are parameters that aren’t obvious by their naming just what they do, and you just have to poke at it for a while. One example is GET /rest/o/{organization_id}/g which has the parameter is_show_detail that is indicated to be a boolean but is an entry field (other api call tests have booleans as a true/false pulldown), and using true or True or false or False or 0 or 1 seems to yield no difference in results.

Today I am wrestling with programatically creating firewall rulesets at the group level which reference organization wide grouped networks. I am finding that the API seems to be unable to do this or if it can, it is inadequately documented.

I am starting simple, with a single rule and named group. The named group is RFC1918 and includes the 3 RFC1918 networks (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).

The ruleset contains one rule.

The rule is to be the lowest level internal rule (last place in the list, so it applies last) and will deny all RFC1918 to all other RFC1918 IPv4 traffic. This is roughly equivalent to disabling inter-VLAN communication, but permits us to add earlier allow rules as an override.

I have a Testing group, where I have manually input all of this. However, upon querying the firewall ruleset, I get data that makes no sense to me, and appears to have no reference at all to the RFC1918 grouped network.

Results from GET /rest/o/{organization_id}/g/{group_id}/firewall_rule_sets:

{
	"resp_code": "SUCCESS",
	"caller_ref": "2025061314045269918202",
	"server_ref": "2025061314045226436664",
	"data": [
		{
			"profile_id": 3,
			"name": "DefaultBlockedRFC1918",
			"device_tag_selection": "none",
			"default_in_action": "accept",
			"default_out_action": "accept",
			"default_internal_action": "drop",
			"sort_order": 9999,
			"rules": [
				{
					"id": 1,
					"name": "Default_Deny_RFC1918",
					"direction": "internal",
					"source_ip": "0.0.0.0",
					"destination_ip": "0.0.0.0",
					"destination_port": 0,
					"protocol": "0",
					"dscp": 0,
					"action": "drop",
					"enable": true,
					"log": true,
					"sort_order": 1
				}
			]
		}
	]
}

As you can see, there appears to be no reference to the RFC1918 grouped network.

Now if I use GET /rest/o/{organization_id}/g/{group_id}/firewall_rule_sets/{profile_id} using profile_id of 3 from above, I get these results:

{
	"resp_code": "SUCCESS",
	"caller_ref": "2025061314291068748926",
	"server_ref": "2025061314291035245114",
	"data": {
		"profile_id": 3,
		"name": "DefaultBlockedRFC1918",
		"device_tag_selection": "none",
		"default_in_action": "accept",
		"default_out_action": "accept",
		"default_internal_action": "drop",
		"sort_order": 9999,
		"rules": [
			{
				"id": 1,
				"name": "Default_Deny_RFC1918",
				"direction": "internal",
				"source_ip": "0.0.0.0",
				"destination_ip": "0.0.0.0",
				"destination_port": 0,
				"protocol": "0",
				"dscp": 0,
				"action": "drop",
				"enable": true,
				"log": true,
				"sort_order": 1
			}
		]
	}
}

Without being able to get a working example dataset out via the API, I cannot know how to create new rulesets that contain the RFC1918 grouped network rule. Additionally, I am concerned that making use of the POST method for “update firewall ruleset” will break the existing RFC1918 reference that is hidden from me.

Am I missing something? I would love to be wrong about this. But ultimately the question is this: how do I go about programatically creating or updating firewall rulesets that reference grouped networks via the IC2 API?

Thanks. At this point I am facing the purgatory of manually creating 20+ rulesets due to this issues.

So experimenting further, using POST /rest/o/{organization_id}/g/{group_id}/firewall_rule_sets/{profile_id} with that profile_id of 3, changing rules[0][‘log’] to false and no other changes, gave me this return:

{
  'caller_ref': '0',
  'resp_code': 'SUCCESS',
  'server_ref': '202506131509254920000647584301',
}

However, when I go into IC2 and check the updated rule, all the RFC1918 references are gone and the rule now just says “any” for source and destination, which is honestly what I expected.

A GET of the same endpoint provides these results:

{
  'default_in_action': 'accept',
  'default_internal_action': 'drop',
  'default_out_action': 'accept',
  'device_tag_selection': 'none',
  'name': 'DefaultBlockedRFC1918',
  'profile_id': 3,
  'rules': [
    {
      'action': 'drop',
      'destination_ip': '0.0.0.0',
      'destination_port': 0,
      'direction': 'internal',
      'dscp': 0,
      'enable': true,
      'id': 1,
      'log': false,
      'name': 'Default_Deny_RFC1918',
      'protocol': '0',
      'sort_order': 1,
      'source_ip': '0.0.0.0',
    },
  ],
  'sort_order': 9999,
}

I’m afraid that either the API needs to be updated to handle grouped networks, and/or the documentation for it needs to be updated to indicate how to manipulate the rulesets that reference grouped networks without breaking them.

Thanks,
Jim

so I have a workaround by creating a lot more rules programatically.

I am able to use the POST method to modify any existing firewall ruleset in a group. I can use the GET method to get the list of firewall rulesets in the group, and then use the profile method of getting presumably more specific (but seemingly identical?) data.

However, no form of the PUT method works to create a new firewall ruleset from scratch. I have even used the test feature in the IC2 API documentation and copied a config from another group and pasted as the data for the create, with no joy. changing the obvious things (profile_id, id, name, etc) doesn’t help. I get some measure of UNDEFINED or INTERNAL ERROR. Once I got a message that made me think not having a profile_id was the cause, but where do you create those if not via the create method? leaving that blank, an empty string, the number 0, a random number, none of that helped.

I am not being paid to debug the API, so I am finding my own workarounds. These workarounds increase the workload of managing the firewall rulesets, but that’s just the way it is right now. I will add that the mounting frustration is eroding my enjoyment of working with Peplink equipment.

So when using the GET method, the json you receive lacks any distinguishing information for an IP Address (/32) vs an IP Network, nor any indicator of how to load a subnet mask.

So the “create” function seems to be totally non-functional.

The “read” function doesn’t show all the behind the scenese information that matters for a firewall rule.

Due to that, the “update” function is hindered in its operation.

I have not even tested the API “delete” function yet.

For my project, I was able to manually go into every group and create a fresh ruleset with no changes other than a name and tag to apply to. Then I was able to use my script to pre-load a lot of stuff. And now, I have to go through each and every ruleset and correct the netmask for all the IP networks.

Disappointed, to say the least.

So I owe an update here. I opened a ticket with Peplink, and the response a few hours later is that they can see the results I see and are getting the engineering team to review this set of API calls.

I just need to be patient now while they look into it.

1 Like