diff --git a/packages/ns-api/Makefile b/packages/ns-api/Makefile index 76ac56c49..04831391b 100644 --- a/packages/ns-api/Makefile +++ b/packages/ns-api/Makefile @@ -144,6 +144,8 @@ define Package/ns-api/install $(INSTALL_DATA) ./files/ns.netifyd.json $(1)/usr/share/rpcd/acl.d/ $(INSTALL_BIN) ./files/ns.controller $(1)/usr/libexec/rpcd/ $(INSTALL_DATA) ./files/ns.controller.json $(1)/usr/share/rpcd/acl.d/ + $(INSTALL_BIN) ./files/ns.conntrack $(1)/usr/libexec/rpcd/ + $(INSTALL_DATA) ./files/ns.conntrack.json $(1)/usr/share/rpcd/acl.d/ $(INSTALL_BIN) ./files/ns.scan $(1)/usr/libexec/rpcd/ $(INSTALL_DATA) ./files/ns.scan.json $(1)/usr/share/rpcd/acl.d/ $(INSTALL_DIR) $(1)/lib/upgrade/keep.d diff --git a/packages/ns-api/README.md b/packages/ns-api/README.md index b70e4349a..c036ed837 100644 --- a/packages/ns-api/README.md +++ b/packages/ns-api/README.md @@ -6325,3 +6325,99 @@ Response example: ] } ``` + +## ns.conntrack + +List and delete conntrack entries. + +### list + +List all conntrack entries: + +```bash +api-cli ns.conntrack list +``` + +Example response: + +```json +{ + "data": [ + { + "destination": "192.168.122.155", + "destination_stats": { + "bytes": "9996", + "packets": "119" + }, + "id": "3363877713", + "protocol": "icmp", + "source": "192.168.122.1", + "source_stats": { + "bytes": "9996", + "packets": "119" + }, + "timeout": "29" + }, + { + "destination": "127.0.0.1", + "destination_port": "8090", + "destination_stats": { + "bytes": "2233", + "packets": "5" + }, + "id": "4275285926", + "protocol": "tcp", + "source": "127.0.0.1", + "source_port": "53740", + "source_stats": { + "bytes": "741", + "packets": "5" + }, + "state": "TIME_WAIT", + "timeout": "5" + } + ] +} +``` + +Fields that might miss from some entries: + +- `start_port` +- `end_port` +- `unreplied` +- `state` + +### drop + +Drop a conntrack entry, use the `id` provided by the `list` command: + +```bash +api-cli ns.conntrack drop --data '{"id": "3363877713"}' +``` + +Example response: + +```json +{ + "message": "success" +} +``` + +Note: if the entry does not exist, the API will still return a `success`, this is to avoid the drop of connection that +already expired. + +## drop_all + +Drop all conntrack entries: + +```bash +api-cli ns.conntrack drop_all +``` + +Example response: + +```json +{ + "message": "success" +} +``` diff --git a/packages/ns-api/files/ns.conntrack b/packages/ns-api/files/ns.conntrack new file mode 100755 index 000000000..75f6adfd9 --- /dev/null +++ b/packages/ns-api/files/ns.conntrack @@ -0,0 +1,48 @@ +#!/usr/bin/python3 + +# +# Copyright (C) 2024 Nethesis S.r.l. +# SPDX-License-Identifier: GPL-2.0-only +# + +import json +import sys + +from nethsec import conntrack +from nethsec.utils import ValidationError, generic_error + +cmd = sys.argv[1] + +if cmd == 'list': + print(json.dumps({ + 'list': {}, + 'drop': { + 'id': '' + }, + 'drop_all': {} + })) +elif cmd == 'call': + action = sys.argv[2] + if action == 'list': + print(json.dumps({ + 'data': conntrack.list_connections() + })) + elif action == 'drop': + data = json.loads(sys.stdin.read()) + if 'id' not in data: + raise ValidationError('id', 'required') + try: + conntrack.drop_connection(data['id']) + except ValueError as e: + # this connection is not found, probably already dropped + pass + except RuntimeError as e: + json.dump(generic_error('command failed'), sys.stdout) + + json.dump({'message': 'success'}, sys.stdout) + elif action == 'drop_all': + try: + conntrack.drop_all_connections() + json.dump({'message': 'success'}, sys.stdout) + except RuntimeError as e: + json.dump(generic_error('command failed'), sys.stdout) diff --git a/packages/ns-api/files/ns.conntrack.json b/packages/ns-api/files/ns.conntrack.json new file mode 100644 index 000000000..a81f251e7 --- /dev/null +++ b/packages/ns-api/files/ns.conntrack.json @@ -0,0 +1,13 @@ +{ + "conntrack-tool": { + "description": "List and manage connection entries using conntrack", + "write": {}, + "read": { + "ubus": { + "ns.conntrack": [ + "*" + ] + } + } + } +}