in cartography/intel/gcp/compute.py [0:0]
def _parse_port_string_to_rule(port, protocol, fw_partial_uri, is_allow_rule):
"""
Takes a string argument representing a GCP firewall rule port or port range and returns a dict that is easier to
load into Neo4j.
Example 1 - single port range:
Input: `'0-65535', 'tcp', fw_id, is_allow_rule=True`
Output: `{fromport: 0, toport: 65535, protocol: tcp, ruleid: fw_id/allow/0to65535tcp}`
Example 2 - single port
Input: `'80', fw_id, is_allow_rule=False`
Output: `{fromport: 80, toport: 80, protocol: tcp, ruleid: fw_id/deny/80tcp}`
Example 3 - ICMP (no ports)
Input: `None, fw_id, is_allow_rule=True`
Output: `{fromport: None, toport: None, protocol: icmp, ruleid: fw_id/allow/icmp}`
:param port: A string representing a single port or a range of ports. Example inputs include '22' or '12345-12349'
:param protocol: The protocol
:param fw_partial_uri: The partial URI of the firewall
:param is_allow_rule: Whether the rule is an `allow` rule. If false it is a `deny` rule.
:return: A dict containing fromport, toport, a ruleid, and protocol
"""
# `port` can be a range like '12345-12349' or a single port like '22'
if port is None:
# Keep the port range as the empty string
port_range_str = ''
fromport = None
toport = None
else:
# Case 1 - port range: '12345-12349'.split('-') => ['12345','12349'].
# Case 2 - single port: '22'.split('-') => ['22'].
port_split = port.split('-')
# Port range
if len(port_split) == 2:
port_range_str = f"{port_split[0]}to{port_split[1]}"
fromport = int(port_split[0])
toport = int(port_split[1])
# Single port
else:
port_range_str = f"{port_split[0]}"
fromport = int(port_split[0])
toport = int(port_split[0])
rule_type = 'allow' if is_allow_rule else 'deny'
return {
'ruleid': f"{fw_partial_uri}/{rule_type}/{port_range_str}{protocol}",
'fromport': fromport,
'toport': toport,
'protocol': protocol
}