Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
434 changes: 263 additions & 171 deletions packages/ns-api/README.md

Large diffs are not rendered by default.

149 changes: 102 additions & 47 deletions packages/ns-api/files/ns.dpi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/python3

#
# Copyright (C) 2023 Nethesis S.r.l.
# Copyright (C) 2026 Nethesis S.r.l.
# SPDX-License-Identifier: GPL-2.0-only
#

Expand All @@ -22,45 +22,66 @@ if cmd == 'list':
},
'list-rules': {},
'add-rule': {
'name': 'str',
'enabled': False,
'device': 'str',
'applications': 'str',
'protocols': 'str'
},
'delete-rule': {
'config-name': 'str'
'action': 'str',
'source': [],
'appgroups': [],
'position': 'str'
},
'edit-rule': {
'config-name': 'str',
'id': 'str',
'name': 'str',
'enabled': False,
'device': 'str',
'applications': 'str',
'protocols': 'str'
'action': 'str',
'source': [],
'appgroups': []
},
'add-exemption': {
'criteria': 'str',
'description': 'str',
'enabled': False
'delete-rule': {
'id': 'str'
},
'delete-exemption': {
'config-name': 'str'
'rename-rule': {
'id': 'str',
'name': 'str'
},
'edit-exemption': {
'config-name': 'str',
'criteria': 'str',
'description': 'str',
'enabled': False
'enable-rule': {
'id': 'str'
},
'list-exemptions': {},
'list-devices': {},
'list-popular': {
'limit': 32,
'page': 32
'disable-rule': {
'id': 'str'
},
'order-rules': {
'order': ['ns_1234', 'ns_5678']
},
'list-application-categories': {},
'list-application-catalog': {},
'list-loaded-applications': {},
'list-protocol-categories': {},
'list-protocol-catalog': {}
'list-protocol-catalog': {},
'list-loaded-protocols': {},
'list-appgroups': {
'search': 'str',
'limit': 32,
'page': 32
},
'add-appgroup': {
'name': 'str',
'applications': [],
'application_categories': [],
'protocols': [],
'protocol_categories': []
},
'edit-appgroup': {
'id': 'str',
'name': 'str',
'applications': [],
'application_categories': [],
'protocols': [],
'protocol_categories': []
},
'delete-appgroup': {
'id': 'str'
}
}))
elif cmd == 'call':
action = sys.argv[2]
Expand All @@ -80,6 +101,14 @@ elif cmd == 'call':
print(json.dumps({'values': content}))
except Exception:
print(json.dumps({}))
elif action == 'list-loaded-applications':
try:
applications = dpi.load_applications()
except Exception:
print(json.dumps(utils.generic_error('applications_not_available')))
else:
print(json.dumps({'values': [{'id': app_id, 'name': app_name}
for app_id, app_name in applications.items()]}))
elif action == 'list-protocol-categories':
try:
with open('/etc/netifyd/netify-protocol-categories.json', 'r') as f:
Expand All @@ -94,6 +123,14 @@ elif cmd == 'call':
print(json.dumps({'values': content}))
except Exception:
print(json.dumps({}))
elif action == 'list-loaded-protocols':
try:
protocols = dpi.load_protocols()
except Exception:
print(json.dumps(utils.generic_error('protocols_not_available')))
else:
print(json.dumps({'values': [{'id': proto_id, 'name': proto_name}
for proto_id, proto_name in protocols.items()]}))
elif action == 'list-applications':
data = json.JSONDecoder().decode(sys.stdin.read())
result = dpi.list_applications(data.get('search', None), data.get('limit', None), data.get('page', 1))
Expand All @@ -102,37 +139,55 @@ elif cmd == 'call':
print(json.dumps({'values': dpi.list_rules(e_uci)}))
elif action == 'add-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.add_rule(e_uci, data['enabled'], data['device'], 'block', data['applications'], data['protocols'])
print(json.dumps({'message': 'success'}))
config_name = dpi.add_rule(e_uci, data['name'], data['enabled'], data['action'],
data.get('source', []), data.get('appgroups', []),
data.get('position', 'bottom'))
print(json.dumps({'id': config_name}))
elif action == 'edit-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
config_name = dpi.edit_rule(e_uci, data['id'], data['name'], data['enabled'], data['action'],
data.get('source', []), data.get('appgroups', []))
print(json.dumps({'id': config_name}))
elif action == 'delete-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.delete_rule(e_uci, data['config-name'])
dpi.delete_rule(e_uci, data['id'])
print(json.dumps({'message': 'success'}))
elif action == 'edit-rule':
elif action == 'rename-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.edit_rule(e_uci, data['config-name'], data['enabled'], data['device'], 'block', data['applications'],
data['protocols'])
dpi.rename_rule(e_uci, data['id'], data['name'])
print(json.dumps({'message': 'success'}))
elif action == 'add-exemption':
elif action == 'enable-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.add_exemption(e_uci, data['criteria'], data['description'], data['enabled'])
dpi.enable_rule(e_uci, data['id'])
print(json.dumps({'message': 'success'}))
elif action == 'delete-exemption':
elif action == 'disable-rule':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.delete_exemption(e_uci, data['config-name'])
dpi.disable_rule(e_uci, data['id'])
print(json.dumps({'message': 'success'}))
elif action == 'edit-exemption':
elif action == 'order-rules':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.edit_exemption(e_uci, data['config-name'], data['criteria'], data['description'], data['enabled'])
print(json.dumps({'message': 'success'}))
elif action == 'list-exemptions':
print(json.dumps({'values': dpi.list_exemptions(e_uci)}))
elif action == 'list-devices':
print(json.dumps({'values': dpi.list_devices(e_uci)}))
elif action == 'list-popular':
print(json.dumps({'values': dpi.order_rules(e_uci, data['order'])}))
elif action == 'list-appgroups':
data = json.JSONDecoder().decode(sys.stdin.read())
result = dpi.list_popular(e_uci, data.get('limit', None), data.get('page', 1))
result = dpi.list_appgroups(e_uci, data.get('search', None), data.get('limit', None),
data.get('page', 1))
print(json.dumps({'values': result}))
elif action == 'add-appgroup':
data = json.JSONDecoder().decode(sys.stdin.read())
config_name = dpi.add_appgroup(e_uci, data['name'], data.get('applications', []),
data.get('application_categories', []), data.get('protocols', []),
data.get('protocol_categories', []))
print(json.dumps({'id': config_name}))
elif action == 'edit-appgroup':
data = json.JSONDecoder().decode(sys.stdin.read())
config_name = dpi.edit_appgroup(e_uci, data['id'], data['name'], data.get('applications', []),
data.get('application_categories', []), data.get('protocols', []),
data.get('protocol_categories', []))
print(json.dumps({'id': config_name}))
elif action == 'delete-appgroup':
data = json.JSONDecoder().decode(sys.stdin.read())
dpi.delete_appgroup(e_uci, data['id'])
print(json.dumps({'message': 'success'}))
except KeyError as e:
print(json.dumps(utils.validation_error(e.args[0], 'required')))
except json.JSONDecodeError:
Expand Down
2 changes: 2 additions & 0 deletions packages/ns-dpi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ define Package/ns-dpi/install
$(INSTALL_BIN) ./files/dpi-license-update.py $(1)/usr/sbin/dpi-license-update
$(INSTALL_BIN) ./files/dpi-data-update.py $(1)/usr/sbin/dpi-data-update
$(INSTALL_BIN) ./files/dpi-update.py $(1)/usr/sbin/dpi-update
$(INSTALL_BIN) ./files/dpi-migrate.py $(1)/usr/sbin/dpi-migrate
$(INSTALL_CONF) ./files/20_dpi $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/21_dpi_migrate $(1)/etc/uci-defaults/21_dpi_migrate
$(INSTALL_BIN) ./files/99-dpi-license-update-cron.uci-defaults $(1)/etc/uci-defaults/99-dpi-license-update-cron
$(INSTALL_BIN) ./files/99-dpi-data-update-cron.uci-defaults $(1)/etc/uci-defaults/99-dpi-data-update-cron
$(INSTALL_DIR) $(1)/usr/share/ns-plug/hooks/register
Expand Down
18 changes: 0 additions & 18 deletions packages/ns-dpi/files/20_dpi
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,6 @@ config main 'config'
option log_blocked '0'
option enabled '0'
option firewall_exemption '0'
list popular_filters 'netify.facebook'
list popular_filters 'netify.amazon-prime'
list popular_filters 'netify.whatsapp'
list popular_filters 'netify.instagram'
list popular_filters 'netify.netflix'
list popular_filters 'netify.telegram'
list popular_filters 'netify.tiktok'
list popular_filters 'netify.youtube'
list popular_filters 'netify.facebook-messenger'
list popular_filters 'netify.twitter'
list popular_filters 'netify.vimeo'
list popular_filters 'netify.snapchat'
list popular_filters 'netify.pinterest'
list popular_filters 'netify.nordvpn'
list popular_filters 'DoT'
list popular_filters 'netify.twitch'
list popular_filters 'netify.teamviewer'
list popular_filters 'DoH'
EOI
fi

Expand Down
13 changes: 13 additions & 0 deletions packages/ns-dpi/files/21_dpi_migrate
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh

#
# Copyright (C) 2026 Nethesis S.r.l.
# SPDX-License-Identifier: GPL-2.0-only
#

# Migrate /etc/config/dpi from the schema used before application groups existed. Safe to run on every
# boot: dpi-migrate is a no-op once there is nothing left in the old schema.

set -e

/usr/sbin/dpi-migrate
3 changes: 2 additions & 1 deletion packages/ns-dpi/files/connlabel.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
3 bulk
4 best_effort
5 video
6 voice
6 voice
7 netify-allowed
Loading
Loading