Library that handles the DPI rules.
From __init__.py:
| Function | add |
Store a new application group. |
| Function | add |
Store a new rule. |
| Function | build |
Build the criteria of a managed rule: the source, when set, ANDed with the union of its groups. |
| Function | delete |
Delete an application group. |
| Function | delete |
Delete a rule and close the gap its priority leaves behind. |
| Function | disable |
Disable a rule, managed or not. |
| Function | edit |
Edit an application group. |
| Function | edit |
Edit a rule. Only rules created through the API can be edited: a rule carrying a hand-written criteria has no source and no group to fill the form with, and rewriting it would change what it matches. |
| Function | enable |
Enable a rule, managed or not. |
| Function | expand |
Expand application groups into the parenthesised OR block of an action criteria. |
| Function | expand |
Expand the source of a rule into values a criteria can match: ranges become CIDR blocks, addresses and networks are left as they are. |
| Function | freeze |
Build the criteria of a rule written before application groups existed, the way dpi-config has always generated it: source, application, protocol and category turned into an expression narrowed to the rule's device, with the VLAN rewrite applied when the device names a VLAN... |
| Function | is |
Check if an application group is referenced by a rule. |
| Function | list |
List every application and protocol a group can be built with, grouped by category. |
| Function | list |
List the application groups, ordered by name. |
| Function | list |
List the rules in priority order, the order they are evaluated in. |
| Function | load |
Reads the applications loaded in memory by the engine, using the netifyd --dump-apps command. |
| Function | load |
Reads the categories loaded in memory by the engine, using the netifyd --dump-categories command. |
| Function | load |
Reads the protocols from the netifyd --dump-protos command. |
| Function | migrate |
Migrate every rule and exemption from the schema used before application groups existed. |
| Function | order |
Reorder every rule, renumbering the priorities densely from the given order. |
| Function | rename |
Rename a rule, managed or not. |
| Constant | APPGROUP |
Undocumented |
| Constant | APPGROUP |
Undocumented |
| Constant | APPGROUP |
Undocumented |
| Constant | DPI |
Undocumented |
| Constant | DPI |
Undocumented |
| Constant | DPI |
Undocumented |
| Constant | DPI |
Undocumented |
| Constant | NETIFYD |
Undocumented |
| Constant | UNCATEGORIZED |
Undocumented |
| Function | __appgroup |
Values a member of the given kind can take, lowercased. |
| Function | __exemption |
Turn a global exemption's criteria into a rule source. A firewall object is expanded into its member addresses; a plain address, network or range is kept as is. |
| Function | __is |
Undocumented |
| Function | __load |
Reads a downloaded catalog, one of the /etc/netifyd/netify-*.json files. |
| Function | __renumber |
Give every rule a dense priority, starting at 1. The generator keeps 0 for its own action, so no user rule can be evaluated before it. |
| Function | __save |
Undocumented |
| Function | __save |
Undocumented |
| Function | __sorted |
Rule sections in priority order. Rules with no priority, i.e. written by hand, go last keeping their config order. |
| Function | __validate |
Validate a group before it is stored. |
| Function | __validate |
Validate the members of one kind, stripping and deduplicating them. |
| Function | __validate |
Validate the groups a rule matches. At least one is required: a rule with a source and no group would be an IP-level rule, which the firewall does better, and a rule with neither would expand to an empty criteria. |
| Function | __validate |
Undocumented |
| Function | __validate |
Validate the source of a rule: addresses, networks and ranges, IPv4 and IPv6 alike. An empty source means the rule matches every host. |
| Constant | __APPGROUP |
Undocumented |
| Constant | __APPGROUP |
Undocumented |
EUci, name: str, applications: list[ str] = None, application_categories: list[ str] = None, protocols: list[ str] = None, protocol_categories: list[ str] = None) -> str:
(source)
¶
Store a new application group.
- Args:
- e_uci: euci instance
- name: name of the group
- applications: list of application names, as the engine reports them
- application_categories: list of application category tags
- protocols: list of protocol names, as the engine reports them
- protocol_categories: list of protocol category tags
- Returns:
- config name of the group created
- Raises:
- ValidationError: if the name or any member is invalid, or if the group has no members
EUci, name: str, enabled: bool, action: str, source: list[ str], appgroups: list[ str], position: str = 'bottom', match_all: bool = False) -> str:
(source)
¶
Store a new rule.
- Args:
- e_uci: euci instance
- name: name of the rule
- enabled: enable the rule
- action: 'block' or 'allow'
- source: list of addresses, networks or ranges, empty to match every host
- appgroups: config names of the application groups the rule matches, at least one unless
match_allis set - position: 'top' to evaluate the rule before every other one, 'bottom' after them
- match_all: the rule matches every flow, narrowed to
sourcewhen one is given. Mutually exclusive withappgroups
- Returns:
- config name of the rule created
- Raises:
- ValidationError: if any argument is invalid
Build the criteria of a managed rule: the source, when set, ANDed with the union of its groups.
- Args:
- e_uci: euci instance
- rule: the rule section, as returned by
uci.get_all
- Returns:
- the expression, or an empty string when the rule matches nothing and must not be emitted
Delete an application group.
- Args:
- e_uci: euci instance
- config_name: config name of the group to delete
- Returns:
- config name of the group deleted
- Raises:
- ValidationError: if the group does not exist or is referenced by a rule
Delete a rule and close the gap its priority leaves behind.
- Args:
- e_uci: euci instance
- config_name: config name of the rule to delete
- Returns:
- config name of the rule deleted
- Raises:
- ValidationError: if the rule does not exist
Disable a rule, managed or not.
- Args:
- e_uci: euci instance
- config_name: config name of the rule to disable
- Returns:
- config name of the rule disabled
- Raises:
- ValidationError: if the rule does not exist
EUci, config_name: str, name: str, applications: list[ str] = None, application_categories: list[ str] = None, protocols: list[ str] = None, protocol_categories: list[ str] = None) -> str:
(source)
¶
Edit an application group.
- Args:
- e_uci: euci instance
- config_name: config name of the group to edit
- name: name of the group
- applications: list of application names, as the engine reports them
- application_categories: list of application category tags
- protocols: list of protocol names, as the engine reports them
- protocol_categories: list of protocol category tags
- Returns:
- config name of the group edited
- Raises:
- ValidationError: if the group does not exist, or if the name or any member is invalid
EUci, config_name: str, name: str, enabled: bool, action: str, source: list[ str], appgroups: list[ str], match_all: bool = False) -> str:
(source)
¶
Edit a rule. Only rules created through the API can be edited: a rule carrying a hand-written criteria has no source and no group to fill the form with, and rewriting it would change what it matches.
- Args:
- e_uci: euci instance
- config_name: config name of the rule to edit
- name: name of the rule
- enabled: enable the rule
- action: 'block' or 'allow'
- source: list of addresses, networks or ranges, empty to match every host
- appgroups: config names of the application groups the rule matches, at least one unless
match_allis set - match_all: the rule matches every flow, narrowed to
sourcewhen one is given. Mutually exclusive withappgroups
- Returns:
- config name of the rule edited
- Raises:
- ValidationError: if the rule does not exist, is not managed, or any argument is invalid
Enable a rule, managed or not.
- Args:
- e_uci: euci instance
- config_name: config name of the rule to enable
- Returns:
- config name of the rule enabled
- Raises:
- ValidationError: if the rule does not exist
Expand application groups into the parenthesised OR block of an action criteria.
Members of several groups are merged and deduplicated; categories are never expanded into their applications, so a category keeps following the signature updates. Groups that do not exist are skipped.
- Args:
- e_uci: euci instance
- config_names: config names of the groups to expand
- Returns:
- the expression, e.g.
(app == 'netify.amazon' || proto == 'http/connect'), or an empty string if the groups hold no member
Expand the source of a rule into values a criteria can match: ranges become CIDR blocks, addresses and networks are left as they are.
- Args:
- values: source entries of the rule
- Returns:
- list of addresses and CIDR blocks
Build the criteria of a rule written before application groups existed, the way dpi-config has
always generated it: source, application, protocol and category turned into an expression narrowed
to the rule's device, with the VLAN rewrite applied when the device names a VLAN. Used by the
migration to freeze a rule's behaviour verbatim before clearing those fields.
- Args:
- e_uci: euci instance
- rule: the rule section, as returned by
uci.get_all
- Returns:
- the semicolon-terminated expression
Check if an application group is referenced by a rule.
- Args:
- e_uci: euci instance
- config_name: config name of the group
- Returns:
- A tuple with: - True if the group is referenced by at least one rule, False otherwise - a list of the rule sections referencing it
List every application and protocol a group can be built with, grouped by category.
Every source has to answer: the engine says what is matchable, the catalogs say how it reads, and a partial answer would silently offer a smaller product than the machine has. So this raises instead of returning what it managed to collect.
The id of an item is what a group stores, and it is the engine name whenever there is one: the catalog tag is only a fallback for an entry that cannot be matched anyway, so it is never a value a client submits. A group is selectable when the category itself can be a group member, which every real category can be and the uncategorised bucket never can. Groups and items are sorted by label, with the uncategorised bucket last; a client translating the category labels has to sort them again.
- Returns:
- dict with the keys "applications" and "protocols", each a list of category groups
- Raises:
- Exception: if the engine cannot be queried or a catalog is missing
EUci, search: str = None, limit: int = None, page: int = 1, used_info: bool = True) -> dict:
(source)
¶
List the application groups, ordered by name.
- Args:
- e_uci: euci instance
- search: search string, matched against the group name
- limit: limit the number of results, all of them if not given
- page: page number
- used_info: include the used and matches info
- Returns:
- dict with the "data" list and the "meta" pagination info
List the rules in priority order, the order they are evaluated in.
Rules hidden with ns_visible '0' are left out: they are system entries the user must not touch.
- Args:
- e_uci: euci instance
- Returns:
- list of dicts, each dict contains the property "id", "name", "enabled", "action", "source", "appgroups", "match_all", "managed" and "index", plus "criteria" for the rules the API did not create
Reads the applications loaded in memory by the engine, using the netifyd --dump-apps command.
- Returns:
- dict of applications, the key is the application id and the value is the application name
Reads the categories loaded in memory by the engine, using the netifyd --dump-categories command.
The dump reports one category per line, as "<id>: <type>: <tag>".
- Returns:
- dict of categories indexed by type, e.g.
{'application': {1: 'adult'}, 'protocol': {2: 'database'}}. Ids are the ones the agent uses internally: they do not match the ids of the downloaded catalogs, so categories must always be crossed by tag.
Reads the protocols from the netifyd --dump-protos command.
- Returns:
- dict of protocols, each dict contains the property "id" and "name"
Migrate every rule and exemption from the schema used before application groups existed.
Each legacy rule (device, application, protocol or category set) is turned into an unmanaged
rule with its behaviour frozen verbatim into criteria — see freeze_legacy_criteria. A rule whose
action is a retired QoS value, or that ends up matching nothing, is dropped instead, with a log line
naming it. A per-rule exemption or log (fields no recent API ever wrote) is removed from the rule,
with a log line as well.
Each global exemption becomes an Allow rule at the top of the list: a managed match-all rule
narrowed to a source when its criteria is a plain address, CIDR or firewall object; an unmanaged
one carrying the criteria verbatim otherwise. Disabled exemptions become disabled rules. The rule
is named after the exemption description, cut to the rule name limit, or Migrated exception N
when it has none.
The exemption section type and popular_filters are then removed.
The changes are committed and the dpi service reloaded right away.
Safe to call unconditionally on every boot: a box with nothing left in the old schema returns without touching UCI.
- Args:
- e_uci: euci instance
Reorder every rule, renumbering the priorities densely from the given order.
The whole set must be listed, hidden rules included: a partial order would silently move the rules left out, which with a paginated list is a rule the caller never saw.
- Args:
- e_uci: euci instance
- order: config names of every rule, in the order they must be evaluated
- Returns:
- the list of the ordered rules
- Raises:
- ValidationError: if the order does not name every rule exactly once
Rename a rule, managed or not.
- Args:
- e_uci: euci instance
- config_name: config name of the rule to rename
- name: new name of the rule
- Returns:
- config name of the rule renamed
- Raises:
- ValidationError: if the rule does not exist or the name is invalid
Undocumented
| Value |
|
Undocumented
| Value |
|
Values a member of the given kind can take, lowercased.
The engine is the authority: only what it has loaded can be matched. The downloaded catalog backs applications up, so that a group stays editable on a machine that lost its premium signatures.
- Args:
- kind: one of the keys of
APPGROUP_MEMBERS
- kind: one of the keys of
- Returns:
- set of accepted values, or None when no source is available and the values cannot be checked
Turn a global exemption's criteria into a rule source. A firewall object is expanded into its member addresses; a plain address, network or range is kept as is.
- Returns:
- the source list, or None when the criteria is empty or does not resolve to at least one address, telling the caller to fall back to an unmanaged rule carrying it verbatim
Reads a downloaded catalog, one of the /etc/netifyd/netify-*.json files.
- Args:
- filename: name of the catalog file inside the netifyd data directory
- Returns:
- list of catalog entries
Give every rule a dense priority, starting at 1. The generator keeps 0 for its own action, so no user rule can be evaluated before it.
EUci, config_name: str, name: str, members: dict[ str, list[ str]]):
(source)
¶
Undocumented
EUci, config_name: str, name: str, enabled: bool, action: str, source: list[ str], appgroups: list[ str], match_all: bool = False):
(source)
¶
Undocumented
Rule sections in priority order. Rules with no priority, i.e. written by hand, go last keeping their config order.
EUci, name: str, applications: list[ str], application_categories: list[ str], protocols: list[ str], protocol_categories: list[ str], config_name: str = None) -> tuple[ str, dict[ str, list[ str]]]:
(source)
¶
Validate a group before it is stored.
- Args:
- e_uci: euci instance
- name: name of the group
- applications: list of application names
- application_categories: list of application category tags
- protocols: list of protocol names
- protocol_categories: list of protocol category tags
- config_name: config name of the group being edited, excluded from the name uniqueness check
- Returns:
- a tuple with the sanitized name and the sanitized members, indexed by UCI list name
- Raises:
- ValidationError: if the name or any member is invalid, or if the group has no members
Validate the members of one kind, stripping and deduplicating them.
- Args:
- kind: one of the keys of
APPGROUP_MEMBERS - values: list of member values
- kind: one of the keys of
- Returns:
- the sanitized list of members
- Raises:
- ValidationError: if a member is empty, holds a character that would break the expression, or is unknown to both the engine and the catalog
EUci, config_names: list[ str], match_all: bool = False) -> list[ str]:
(source)
¶
Validate the groups a rule matches. At least one is required: a rule with a source and no group would be an IP-level rule, which the firewall does better, and a rule with neither would expand to an empty criteria.
match_all is the way out of that requirement, and the only one: a rule that matches every flow
names no group by definition, so naming one at the same time is a contradiction, not a narrowing.