From 1a324f0503edd2f55ed2243c12f31363fa9d2247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Benko?= Date: Thu, 13 Apr 2023 16:09:06 +0200 Subject: [PATCH 1/5] luci-app-ipfixprobe: add MTU field, validation and reordering Add MTU field as it was present in `init.d` script, but couldn't be changed in LuCI. Most fields are validated now. Some fields are reordered for better user experience. --- .../resources/view/services/ipfixprobe.js | 92 ++++++++++++++----- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js b/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js index e8ba9f8..9a7f176 100644 --- a/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js +++ b/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js @@ -3,8 +3,28 @@ 'require uci'; 'require view'; 'require form'; +'require validation'; 'require tools.widgets as widgets'; +function validatePowerOf2(sid, s) { + if (s == null || s == '') + return true; + + var x = validation.parseInteger(s); + + if (isNaN(x) || x < 1) { + // Must be unsigned integer + return _('Expecting: positive integer value'); + } + + if (Math.log2(x) % 1 !== 0) { + // Must be power of 2 + return _('Expecting: power of 2, e.g. 16, 128, 2048,...'); + } + + return true; +} + return view.extend({ render: function(data) { var m, s, o; @@ -19,19 +39,23 @@ return view.extend({ s.tab('ipfix', 'IPFIX Collector'); s.tab('advanced', 'Advanced options'); - o = s.taboption("main", widgets.DeviceSelect, "interfaces", _("Monitored interface")); + o = s.taboption('main', form.Flag, 'enabled', _('Enabled')); + o.default = '0'; + o.rmempty = false; + + o = s.taboption('main', widgets.DeviceSelect, 'interfaces', _('Monitored interface')); o.multiple = true; o.noaliases = true; o.rmempty = false; o = s.taboption('main', form.DynamicList, 'plugins', _('List of plugins'), - _('Enable one or more processing plugins. Plugin with parameters must be entered as a custom string, see manual of ipfixprobe for details - https://github.com/CESNET/ipfixprobe/')); + _('Enable one or more processing plugins. Plugin with parameters must be entered as a custom string, see manual of ipfixprobe for details - https://github.com/CESNET/ipfixprobe/')); o.rmempty = false; o.value('basic', 'Basic'); o.value('bstats', 'BSTATS (burst packet stats)'); o.value('dns', 'DNS'); o.value('dnssd', 'DNS-Service Discovery'); - o.value('dnssd:txt', 'DNS-Service Discovery with extexded TXT'); + o.value('dnssd;txt', 'DNS-Service Discovery with extexded TXT'); o.value('http', 'HTTP'); o.value('idpcontent', 'IDPCONTENT (initial data packets content)'); o.value('netbios', 'Netbios'); @@ -52,60 +76,78 @@ return view.extend({ o.default = '0'; o.rmempty = false; - o = s.taboption('main', form.Flag, 'enabled', _('Enabled')); - o.default = '0'; - o.rmempty = false; - o = s.taboption('ipfix', form.Value, 'ipfix_host', _('IPFIX Collector address')); + o.datatype = 'host'; o = s.taboption('ipfix', form.Value, 'ipfix_port', _('IPFIX Collector port')); + o.datatype = 'port'; + + o = s.taboption('ipfix', form.Value, 'ipfix_mtu', _('IPFIX Collector MTU')); + o.datatype = 'uinteger'; + o.default = '1452'; + o.rmempty = false; o = s.taboption('ipfix', form.Flag, 'ipfix_udp', _('Use UDP')); o.default = '1'; o.rmempty = false; o = s.taboption('ipfix', form.Value, 'link', _('Observation ID'), _('Identification of link')); + o.datatype = 'uinteger'; o.default = '1'; o.rmempty = false; o = s.taboption('ipfix', form.Value, 'dir', _('Interface'), _('Identification of interface')); + o.datatype = 'uinteger'; o.default = '0'; o.rmempty = false; - o = s.taboption('advanced', form.Value, 'raw_blocks', _('Number of blocks'), - _('Number of allocated blocks for capturing from NIC')); - o.default = '3'; - - o = s.taboption('advanced', form.Value, 'raw_packetsinblock', _('Packets in block'), - _('Number of packets in a block read from NIC')); - o.default = '10'; - o = s.taboption('advanced', form.Value, 'active_timeout', _('Active timeout'), - _('Split long flows into at most N seconds flow records')); + _('Split long flows into at most N seconds flow records.')); + o.datatype = 'uinteger'; o.default = '300'; o = s.taboption('advanced', form.Value, 'inactive_timeout', _('Inactive timeout'), - _('Export a flow record after N seconds of inactivity')); + _('Export a flow record after N seconds of inactivity.')); + o.datatype = 'uinteger'; o.default = '30'; - o = s.taboption('advanced', form.Value, 'cache_size', _('Size of flow cache'), - _('Number of entries given by an exponent 2**N')); + o = s.taboption('advanced', form.Value, 'raw_blocks', _('Number of blocks'), + _('Number of allocated blocks for capturing from NIC.')); + o.datatype = 'uinteger'; + o.default = '2'; + + o = s.taboption('advanced', form.Value, 'raw_packetsinblock', _('Packets in block'), + _('Number of packets in a block read from NIC.')); + o.datatype = 'uinteger'; o.default = '10'; + o = s.taboption('advanced', form.Value, 'cache_size', _('Size of flow cache'), + _('Number of entries. Must be power of 2 (i.e. 2**N).')); + o.default = '1024'; + o.validate = validatePowerOf2; + o = s.taboption('advanced', form.Value, 'cache_line', _('Size of flow cache line'), - _('Number of entries given by an exponent 2**N')); - o.default = '2'; + _('Number of entries. Must be power of 2 (i.e. 2**N).')); + o.default = '4'; + o.validate = validatePowerOf2; - o = s.taboption('advanced', form.Flag, 'respawn', _('Respawn')); + o = s.taboption('advanced', form.Flag, 'respawn', _('Respawn'), + _('Enable respawn of crashed process.')); o.default = '1'; - o = s.taboption('advanced', form.Value, 'respawn_threshold', _('Respawn threshold')); + o = s.taboption('advanced', form.Value, 'respawn_threshold', _('Respawn threshold'), + _('Timeout in seconds for restarting a service after it closes.')); + o.datatype = 'uinteger'; o.default = '3600'; - o = s.taboption('advanced', form.Value, 'respawn_timeout', _('Respawn timeout')); + o = s.taboption('advanced', form.Value, 'respawn_timeout', _('Respawn timeout'), + _('Maximum time in seconds to wait for a process respawn to complete.')); + o.datatype = 'uinteger'; o.default = '5'; - o = s.taboption('advanced', form.Value, 'respawn_retry', _('Respawn retry')); + o = s.taboption('advanced', form.Value, 'respawn_retry', _('Respawn retry'), + _('Maximum number of times to attempt respawning before giving up, 0 means never stop trying to respawn.')); + o.datatype = 'uinteger'; o.default = '5'; o = s.taboption('advanced', form.Flag, 'core', _('Core dumps')); From b6a397f0d1c646a8baa87d619558d1908c34e8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Benko?= Date: Thu, 13 Apr 2023 16:10:54 +0200 Subject: [PATCH 2/5] ipfixprobe: validate parameters using `uci_load_validate` Also add support for non-default `raw_blocks` and `raw_packetsinblock`. --- net/ipfixprobe/files/init.d/ipfixprobe | 52 ++++++++++++++------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/net/ipfixprobe/files/init.d/ipfixprobe b/net/ipfixprobe/files/init.d/ipfixprobe index fcae224..ce39bdf 100755 --- a/net/ipfixprobe/files/init.d/ipfixprobe +++ b/net/ipfixprobe/files/init.d/ipfixprobe @@ -1,6 +1,6 @@ #!/bin/sh /etc/rc.common # ipfixprobe, IPFIX flow exporter -# Copyright (C) 2022 CESNET +# Copyright (C) 2022-2023 CESNET # # How to use: @@ -23,25 +23,27 @@ PROG=/usr/bin/ipfixprobe validate_section_ipfixprobe() { uci_load_validate ipfixprobe ipfixprobe "$1" "$2" \ + 'enabled:bool:0' \ 'interfaces:list(string)' \ 'plugins:list(string)' \ + 'split_biflow:bool:0' \ 'ipfix_host:host:127.0.0.1' \ 'ipfix_port:port:4739' \ 'ipfix_udp:bool:1' \ - 'cache_size:integer' \ - 'cache_line:integer' \ - 'active_timeout:integer' \ - 'inactive_timeout:integer' \ - 'link:integer' \ - 'dir:integer' \ - 'split_biflow:bool:0' \ - 'ipfix_mtu:integer:1452' \ + 'ipfix_mtu:uinteger:1452' \ + 'link:uinteger' \ + 'dir:uinteger' \ + 'active_timeout:uinteger:300' \ + 'inactive_timeout:uinteger:30' \ + 'raw_blocks:uinteger:2' \ + 'raw_packetsinblock:uinteger:10' \ + 'cache_size:uinteger:1024' \ + 'cache_line:uinteger:4' \ 'respawn:bool:1' \ - 'respawn_threshold:integer:3600' \ - 'respawn_timeout:integer:5' \ - 'respawn_retry:integer:5' \ - 'core:bool:0' \ - 'enabled:bool:0' + 'respawn_threshold:uinteger:3600' \ + 'respawn_timeout:uinteger:5' \ + 'respawn_retry:uinteger:5' \ + 'core:bool:0' } handle_interface() { @@ -60,9 +62,14 @@ ipfixprobe_profile() { local PROFILE="$1" + [ "$2" = 0 ] || { + echo "Validation failed" + return 1 + } + if [ "$enabled" -eq 0 ]; then logger -p daemon.notice -t ipfixprobe "ipfixprobe profile $PROFILE disabled" - return 1 + return 0 else logger -p daemon.notice -t ipfixprobe "ipfixprobe profile $PROFILE enabled" fi @@ -71,16 +78,16 @@ ipfixprobe_profile() procd_set_param command "$PROG" - config_list_foreach "$PROFILE" interfaces handle_interface "${raw_blocks:-2}" "${raw_packetsinblock:-10}" - config_list_foreach "$PROFILE" plugins handle_plugins "" + config_list_foreach "$PROFILE" interfaces handle_interface "${raw_blocks}" "${raw_packetsinblock}" + config_list_foreach "$PROFILE" plugins handle_plugins "" - [ "${ipfix_udp:-0}" -eq 1 ] && UDP_PARAM=";u" - [ "${split_biflow:-0}" -eq 1 ] && SPLIT_PARAM=";S" + [ "${ipfix_udp}" -eq 1 ] && UDP_PARAM=";u" + [ "${split_biflow}" -eq 1 ] && SPLIT_PARAM=";S" - procd_append_param command -o "ipfix;h=$ipfix_host;p=${ipfix_port:-4739};I=${link:-0};d=${dir:-0}$UDP_PARAM;m=${ipfix_mtu:-1458}" - procd_append_param command -s "cache;s=${cache_size:-10};l=${cache_line:-2};a=${active_timeout:-300};i=${inactive_timeout:-30}$SPLIT_PARAM" + procd_append_param command -o "ipfix;h=$ipfix_host;p=${ipfix_port};I=${link};d=${dir}$UDP_PARAM;m=${ipfix_mtu}" + procd_append_param command -s "cache;s=${cache_size};l=${cache_line};a=${active_timeout};i=${inactive_timeout}$SPLIT_PARAM" - procd_set_param limits core="${core:-0}" + procd_set_param limits core="${core}" procd_set_param stdout 1 procd_set_param stderr 1 procd_close_instance @@ -96,4 +103,3 @@ service_triggers() { procd_add_reload_trigger "$NAME" procd_add_validation validate_section_ipfixprobe } - From 2b02b0d6516b4741aed0a0582b20780caf4bb95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Benko?= Date: Thu, 13 Apr 2023 17:33:40 +0200 Subject: [PATCH 3/5] ipfixprobe: simplify default UCI configuration Remove unnecessary options and disable it by default, so there's no unexpected behaviour. --- net/ipfixprobe/files/config/ipfixprobe | 100 +++++++------------------ 1 file changed, 26 insertions(+), 74 deletions(-) diff --git a/net/ipfixprobe/files/config/ipfixprobe b/net/ipfixprobe/files/config/ipfixprobe index a291933..9e082c3 100644 --- a/net/ipfixprobe/files/config/ipfixprobe +++ b/net/ipfixprobe/files/config/ipfixprobe @@ -1,93 +1,45 @@ # NEMEA ipfixprobe -# Copyright (C) 2022 CESNET +# Copyright (C) 2022-2023 CESNET -# -# Available options for profiles, "list" options can be used repeatedly: +# Available options for profiles, 'list' options can be used repeatedly: # list interfaces - list of NIC, e.g., eth0, enp0s1, ... # list plugins - list of plugin names, see 'ipfixprobe -h process' for help # ipfix_host - address of IPFIX collector # ipfix_port - port of IPFIX collector, default: 4739 # ipfix_udp - 1 to export to IPFIX collector via UDP, 0 via TCP -# cache_size - size of flow cache as an exponent 2**N, default: 10 -# cache_line - size of flow cache line as an exponent 2**N, default: 2 +# cache_size - size of flow cache as exponent of 2, default: 1024 +# cache_line - size of flow cache line as exponent of 2, default: 4 # active_timeout - active timeout in seconds, default: 300 # inactive_timeout - inactive timeout in seconds, default: 30 -# link - identification of link/router -# dir - identification of direction/NIC +# link - unsigned integer as identification of link/router +# dir - unsigned integer as identification of direction/NIC # split_biflow - 1 to split biflow to uniflow, default: 0 to use biflow -# ipfix_mtu - size of max transmission unit (MTU), default: 1458 +# ipfix_mtu - size of max transmission unit (MTU), default: 1452 # # respawn - enable respawn of crashed process # respawn_threshold - timeout in seconds for restarting a service after it closes # respawn_timeout - max time in seconds to wait for a process respawn to complete # respawn_retry - max number of attempts to respawn before giving up, 0 means newer stop trying to respawn -# core - size of coredump, "0" - not generate, "unlimited" - unlimited size +# core - size of coredump, '0' - not generate, 'unlimited' - unlimited size # # enabled - 1 to enable start daemon instance for that profile, NOTE: if profile is directly specified for start script # (example: '/etc/init.d/ipfixprobe start wan profileX profileY lan'), this option is ignored -# - -config profile lan - list interfaces br-lan - #list interfaces eth0 - list plugins "basicplus" - list plugins "dns" - list plugins "http" - list plugins "pstats" - list plugins "ovpn" - list plugins "wg" - list plugins "dnssd;txt" - list plugins "ssdp" - list plugins "tls" - list plugins "quic" - option raw_blocks 3 - option raw_packetsinblock 10 - option ipfix_host 127.0.0.1 - option ipfix_port 4739 - option ipfix_enable 1 - option ipfix_udp 1 - option cache_size 14 - option cache_line 2 - option active_timeout 300 - option inactive_timeout 30 - option link 0x1 - option dir 1 - option split_biflow 0 - option respawn 1 - option respawn_threshold 3600 - option respawn_timeout 5 - option respawn_retry 5 - option core 0 - option enabled 1 - -config profile wan - list interfaces eth0 - list plugins "basicplus" - list plugins "dns" - list plugins "http" - list plugins "pstats" - list plugins "ovpn" - list plugins "wg" - list plugins "dnssd;txt" - list plugins "ssdp" - list plugins "tls" - list plugins "quic" - option raw_blocks 3 - option raw_packetsinblock 10 - option ipfix_host 127.0.0.1 - option ipfix_port 4739 - option ipfix_udp 1 - option cache_size 14 - option cache_line 2 - option active_timeout 300 - option inactive_timeout 30 - option link 0x1 - option dir 0 - option split_biflow 0 - option respawn 1 - option respawn_threshold 3600 - option respawn_timeout 5 - option respawn_retry 5 - option core 0 - option enabled 1 +config profile 'lan' + option enabled '0' + list interfaces 'br-lan' + list plugins 'basicplus' + list plugins 'dns' + list plugins 'http' + list plugins 'pstats' + list plugins 'ovpn' + list plugins 'wg' + list plugins 'dnssd;txt' + list plugins 'ssdp' + list plugins 'tls' + list plugins 'quic' + option ipfix_host '127.0.0.1' + option ipfix_port '4739' + option ipfix_udp '1' + option link '1' + option dir '1' From e5bea238ec6e0bae7618bfd0c4cc80b2cfa66512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Benko?= Date: Fri, 21 Apr 2023 10:46:39 +0200 Subject: [PATCH 4/5] luci-app-ipfixprobe: fix `cache_size` and `cache_line` --- .../resources/view/services/ipfixprobe.js | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js b/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js index 9a7f176..85d1f50 100644 --- a/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js +++ b/luci-app-ipfixprobe/htdocs/luci-static/resources/view/services/ipfixprobe.js @@ -6,25 +6,6 @@ 'require validation'; 'require tools.widgets as widgets'; -function validatePowerOf2(sid, s) { - if (s == null || s == '') - return true; - - var x = validation.parseInteger(s); - - if (isNaN(x) || x < 1) { - // Must be unsigned integer - return _('Expecting: positive integer value'); - } - - if (Math.log2(x) % 1 !== 0) { - // Must be power of 2 - return _('Expecting: power of 2, e.g. 16, 128, 2048,...'); - } - - return true; -} - return view.extend({ render: function(data) { var m, s, o; @@ -122,14 +103,14 @@ return view.extend({ o.default = '10'; o = s.taboption('advanced', form.Value, 'cache_size', _('Size of flow cache'), - _('Number of entries. Must be power of 2 (i.e. 2**N).')); - o.default = '1024'; - o.validate = validatePowerOf2; + _('Number of entries given by an exponent 2**N.')); + o.datatype = 'and(uinteger,min(4),max(30))'; + o.default = '10'; o = s.taboption('advanced', form.Value, 'cache_line', _('Size of flow cache line'), - _('Number of entries. Must be power of 2 (i.e. 2**N).')); - o.default = '4'; - o.validate = validatePowerOf2; + _('Number of entries given by an exponent 2**N.')); + o.datatype = 'and(uinteger,max(30))'; + o.default = '2'; o = s.taboption('advanced', form.Flag, 'respawn', _('Respawn'), _('Enable respawn of crashed process.')); From 5c76a32a3e18a00e824efe6219628a3e756e6ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Benko?= Date: Fri, 21 Apr 2023 10:47:28 +0200 Subject: [PATCH 5/5] ipfixprobe: fix `cache_size` and `cache_line` --- net/ipfixprobe/files/init.d/ipfixprobe | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipfixprobe/files/init.d/ipfixprobe b/net/ipfixprobe/files/init.d/ipfixprobe index ce39bdf..db1fb95 100755 --- a/net/ipfixprobe/files/init.d/ipfixprobe +++ b/net/ipfixprobe/files/init.d/ipfixprobe @@ -37,8 +37,8 @@ validate_section_ipfixprobe() 'inactive_timeout:uinteger:30' \ 'raw_blocks:uinteger:2' \ 'raw_packetsinblock:uinteger:10' \ - 'cache_size:uinteger:1024' \ - 'cache_line:uinteger:4' \ + 'cache_size:uinteger:10' \ + 'cache_line:uinteger:2' \ 'respawn:bool:1' \ 'respawn_threshold:uinteger:3600' \ 'respawn_timeout:uinteger:5' \