From d4d55235dadffbc9ab50f02d9bbe042f7d817226 Mon Sep 17 00:00:00 2001 From: mqus <8398165+mqus@users.noreply.github.com> Date: Sun, 4 Nov 2018 15:01:52 +0100 Subject: [PATCH 1/6] Add _nft (iptables successor) completion Some things to note here: 1.: There are bugs in the code as I'm no expert on zsh completion *at all*. I just trial-and-error'd a big part of it. 2.: Some things are not done here (marked with a `TODO`), namely the statement syntax of some `nft add` commands. 3.: Some completions try to complete existing chain names/rule handles/table names. For this you either have to be root or use sudo AND enable the gain-privileges zstyle (otherwise this will not work) 4.: I also found the nft man page to be somewhat lacking so there might be some edge case completions which are plain wrong. --- src/_nft | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 src/_nft diff --git a/src/_nft b/src/_nft new file mode 100644 index 0000000..cde4d10 --- /dev/null +++ b/src/_nft @@ -0,0 +1,465 @@ +#compdef nft + +_nft(){ +local -a rules states prev args families options descriptors +local state="start" line nextstate cmd_obj cmd_subcmd cmd_fam cmd_tab cmd_chain #curcontext="$curcontext" + +options=( + '(-)'{-h,--help}'[show help]' \ + '(-)'{-v,--version}'[print version information]' \ + "(-i --interactive)"{-i,--interactive}'[read input from interactive CLI]: :->end' \ + "(-f --file)"{-f,--file}'[Read input from ]:nftables rule file:_files' \ + '(-c --check -n --numeric -N)'{-c,--check}'[check commands validity without actually applying the changes]' \ + '(-j --json)'{-j,--json}'[format output in json]' \ + '(-c --check -N)*'{-n,--numeric}'[can be specified up to 3 times, Shows 1:network addresses(default behaviour), 2:Internet services (port numbers) and 3:protocols, user IDs, and group IDs numerically]' \ + '(-s --stateless)'{-s,--stateless}'[omit stateful information of ruleset]' \ + '(-N -n --numeric -c --check)'-N'[translate IP addresses to names]' \ + '(-a --handle)'{-a,--handle}'[output rule handle]' \ + '(-e --echo)'{-e,--echo}'[echo what has been added, inserted or replaced]' \ + {-I,--includepath}'[add to the paths searched for include files. Default is /usr/share]:include directory:_path_files -/' \ +) + +# start a state machine. The state is modified by _arguments if the +# current argument (descriptors) cannot be completed. Each state has to define is successive state and the +# 'descriptors' for _arguments, which essentially tells _arguments how to complete +_i=0 +while true;do + (( _i+=1 )) + #Guard for endless loops + [[ $_i -gt 100 ]] && return 1 + + descriptors=() + nextstate="end" + case $state in + (start) + ##if line is empty (at the start) or ends with semicolon, autocomplete subcommands, + # else if we are after a space,complete a semicolon (end the current nft command) and start anew + if [[ $line[1] = "" || $line[1] =~ ';$' ]] ; then + descriptors=( ":: :_nft_subcommands" ) + nextstate="category" + else + if [[ $words =~ ' $' ]]; then + descriptors=(':: :(\;)') + else + descriptors=(':argument: ') + fi + nextstate="start" + fi + ;; + (category) + case $line[1] in + (add | list | flush | delete | create | rename | insert | replace | reset) + descriptors=( ":: :_nft_${line[1]}" ) + nextstate=$line[1] + ;; + (monitor) + descriptors=( ":: : _nft_mon_filter" ) + nextstate="mon1" + ;; + (export) + descriptors=( ":: :(ruleset)" ":: :_nft_out_format" ) + nextstate="preend" + ;; + (describe) + descriptors=( ":expression: ") + nextstate="start" #x restart + ;; + (*) + return 1; + ;; + esac + + #descriptors=( "(ruleset)" ) + #nextstate="end" + ;; + (mon1) + case $line[1] in + (new | destroy) +# descriptors=( ":: :_nft_mon_keywords" ":: :_nft_out_format") + descriptors=( ":: : _nft_mon_keywords") + nextstate="mon1" + ;; + (tables | chains | sets | rules | elements | ruleset) + descriptors=( ":: : _nft_out_format") + nextstate="preend" + ;; + esac + ;; + #all completions for create and insert match with the completions of add + (create | insert) + state="add" + ;| + #all completions for reset and flush match with the completions of list + (reset | flush) + state="list" + ;| + #(add(^table)/create(^table)/delete/flush(^ruleset)/insert/list(^ruleset)/rename/replace)[family]table + (reset | delete | insert | rename | replace | add | create | flush | list) + if [[ $state = "add" && $line[1] = "table" ]]; then + descriptors=( ":: :_nft_families" ":table name:") + nextstate="start" #x restart + elif [[ $state = "list" && ( $line[1] = "ruleset" || $line[1] = "tables" ) ]]; then + descriptors=( ":: :_nft_families") + nextstate="start" #x restart + elif [[ $state = "delete" && $line[1] = "table" ]]; then + descriptors=(": : _nft_table all-handle") + nextstate="tcomplete-delete-table" + else + cmd_obj=$line[1] + cmd_subcmd=$state + descriptors=(": : _nft_table all") + nextstate="tcomplete" + fi + ;; + (tcomplete-delete-table) + # if only a family was completed, complete the table name. + case $line[1] in + (arp | bridge | inet | ip | ip6 | netdev) + descriptors=(": : _nft_table ${line[1]}-handle") + cmd_fam=$line[1] + ;; + # else, complete nothing and go to the next state. default family is 'ip' + (*) + descriptors=() + cmd_fam="ip" + ;; + esac + nextstate="delete-table" + ;; + (tcomplete) + # if only a family was completed, complete the table name. + case $line[1] in + (arp | bridge | inet | ip | ip6 | netdev) + descriptors=(": : _nft_table ${line[1]}") + cmd_fam=$line[1] + ;; + # else, complete nothing and go to the next state. default family is 'ip' + (*) + descriptors=() + cmd_fam="ip" + ;; + esac + nextstate="$cmd_subcmd-$cmd_obj" + ;; + (list-table) + descriptors=(":: :(\;)") + nextstate="start" + ;; + (delete-table) + if [[ $line[1] == "handle" ]]; then + descriptors=(":table handle: _nft_table_handle $cmd_fam" ) + else + descriptors=() + fi + nextstate="start" + ;; + (delete-chain | delete-set | delete-quota | delete-counter | delete-ct\\ helper) + cmd_tab=$line[1] + descriptors=(": : _nft_obj $cmd_fam $cmd_tab $cmd_obj true") + nextstate="delete-obj-handle" + ;; + (delete-obj-handle) + if [[ $line[1] == "handle" ]]; then + descriptors=(": : _nft_obj_handle $cmd_fam $cmd_tab $cmd_obj") + else + descriptors=(": :(\;)") + fi + nextstate="start" + ;; + (add-chain) + descriptors=(":chain name:") + nextstate="start" + ;; + (rename-chain) + cmd_tab=$line[1] + descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + nextstate="add-chain" + ;; + (replace-rule | delete-rule) + cmd_tab=$line[1] + descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + nextstate="repdel-rule" + ;; + (repdel-rule) + cmd_chain=$line[1] + descriptors=(": :(handle)" ": : _nft_rule_handle $cmd_fam $cmd_tab ${line[1]}") + if [[ $cmd_subcmd = "replace" ]];then + nextstate="rule-stmt" + else + nextstate="start" + fi + ;; + (add-rule) + cmd_tab=$line[1] + descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + nextstate="add-rule-2" + ;; + (add-rule-2) + cmd_chain=$line[1] + descriptors=(": :(handle index position)") + nextstate="add-rule-3" + ;; + (add-rule-3) + case $line[1] in + (index | position) + descriptors=(":${line[1]}:") + ;; + (handle) + descriptors=(": : _nft_rule_handle $cmd_fam $cmd_tab $cmd_chain") + ;; + (*) + descriptors=() + ;; + esac + nextstate="rule-stmt" + ;; + (rule-stmt) + #TODO + # _nft_rule $cmd_fam $cmd_tab $cmd_chain\ + # && return 0; + descriptors=":expression: " + nextstate="start" + ;; + (list-set | list-map | delete-map | list-chain | list-flowtable | delete-flowtable | list-ct\\ helper | list-counter | list-quota | list-meter) + cmd_tab=$line[1] + descriptors=(": : _nft_obj $cmd_fam $cmd_tab $cmd_obj false") + nextstate="start" + ;; + #TODO: + #(add-element | delete-element) + #(add-set | add-map) + #(add-flowtable) + #("add-ct\ helper") + #(add-counter) + #(add-quota) + + (*) + return 1; + ;; + esac + _arguments -C -s \ + "${options[@]}" \ + "${descriptors[@]}" \ + "*:: :->$nextstate" \ + && return 0; + +done +} # end _nft + +_nft_subcommands(){ + local commands=( + 'add:add a table, chain, rule, set, map, or object' + 'list:list a ruleset, table, chain, set, map, or object' + 'flush:flush (delete everything from) a ruleset, table, chain, set, or map' + 'export:print the ruleset in a machine readable format (json or xml)' + 'delete:delete a table, chain, rule, set, element, map, or object' + 'create:similar to add but returns an error for existing chain' + 'rename:rename the specified chain' + 'insert:similar to the add command, but the rule is prepended to the beginning of the chain or before the rule at the given position' + 'replace:similar to the add command, but replaces the specified rule' + 'reset:list-and-reset stateful object' + 'monitor:listen to Netlink events' + 'describe:show information about the type of an expression and its data type' + ) + _describe -t commands 'nft subcommands' commands "${expl[@]}" +} +_nft_mon_filter(){ + local filter=( + 'new:show only events of created objects' + 'destroy:show only events of deleted objects' + ) + _describe -t filter 'nft monitor' filter -J "action filter" "${expl[@]}" + _nft_mon_keywords +} + +_nft_mon_keywords(){ + local objs=( + 'tables:show table events' + 'chains:show chain events' + 'sets:show set events' + 'rules:show rule events' + 'elements:show only events of element objects' + 'ruleset:show ruleset events, such as table, chain, rule, set, counters and quotas' + ) + _describe -t objs 'nft monitor' objs -J "object filter" "${expl[@]}" + _nft_out_format +} + +_nft_out_format(){ + local commands=( + 'json:format output to JSON' + 'xml:format output to XML' + ) + _describe -t commands "output format" commands -J "output format options" "${expl[@]}" +} + +_nft_add(){ + local commands=( + 'table:add a new table' + 'flowtable:add a new flowtable' + 'chain:add a chain to a table' + 'rule:add a rule to an existing chain' + 'set:add a set to a table' + 'map:add a map to a table' + 'element:add one or multiple element(s) to a set or map' + 'ct\ helper:add a ct helper to a table' + 'counter:add a named counter to a table' + 'quota:add a named quota helper to a table' + ) + _describe -t commands 'nft add' commands "$@" +} + +_nft_create(){ + local commands=( + "table:add a table, but return an error if it already exists" + "chain:add a chain to a table, but return an error if it already exists" + "flowtable:add a flowtable, but return an error if it already exists" + ) + _describe -t commands 'nft create' commands "$@" +} + +_nft_delete(){ + local commands=( + "table:delete the specified table" + "chain:delete the specified chain, chain must be empty and mustn't be used as jump target" + "rule:delete the specified rule, rule must be referrable to by a handle" + "set:delete the specified set" + "map:delete the specified map" + "element:delete element(s) from the specified set/map" + "flowtable:delete the specified flowtable" + "ct\ helper:delete the specified ct helper" + "counter:delete the specified counter" + "quota:delete the specified quota" + ) + _describe -t commands 'nft delete' commands "$@" +} + +_nft_flush(){ + local commands=( + "ruleset:clear the whole ruleset, including removing all tables and containing objects" + "table:flush all chains and rules of the specified table" + "chain:flush all rules of the specified chain" + "set:remove all elements from the specified set" + "map:remove all elements from the specified map" + ) + _describe -t commands 'nft flush' commands "$@" +} + +_nft_insert(){ + local commands=( + "rule:prepend a rule to the beginning of the chain or before the rule with the given handle" + ) + _describe -t commands 'nft insert' commands "$@" +} + +_nft_list(){ + local commands=( + "ruleset:print the ruleset in human-readable format" + "tables:list all tables (undocumented)" + "table:list all chains and rules of the specified table" + "chain:list all rules of the specified chain" + "set:display the elements in the specified set" + "map:display the elements in the specified map" + "flowtable:list all flowtables" + "ct\ helper:display stateful information the ct helper holds" + "counter:display stateful information the counter holds" + "quota:display stateful information the quota holds" + ) + _describe -t commands 'nft list' commands "$@" +} + +_nft_rename(){ + local commands=( + "chain:replace a chain" + ) + _describe -t commands 'nft rename' commands "$@" +} + +_nft_replace(){ + local commands=( + "rule:replace a rule" + ) + _describe -t commands 'nft replace' commands "$@" +} + +_nft_reset(){ + local commands=( + 'ct\ helper:reset and list a ct helper to a table' + 'counter:reset and list a counter from a table' + 'quota:reset and list a quota object a table' + ) + _describe -t commands 'nft reset' commands "$@" +} +_nft_families(){ + local commands=( + "ip:IPv4 address family" + "ip6:IPv6 address family" + "inet:internet (IPv4+IPv6) address family" + "arp:ARP address family, handling IPv4 ARP packets" + "bridge:Bridge address family, handling packets which traverse a bridge device" + "netdev:Netdev address family, handling packets from ingress" + ) + _describe -t commands 'nft families' commands "$@" +} + +_nft_table(){ + #$1 can be: all all-handle -handle + local tables=() + if [[ "$1" =~ "^all" ]]; then + tables+=( ${(f)"$(_call_program -p nft-tables nft list tables 2>/dev/null \ + | cut -d\ -f2 |sort|uniq -u )"} ) + 1="${1/all/ip}" + fi + if [[ "$1" =~ "-handle$" ]]; then + tables+=("handle") + #remove -handle from $1 to be able to complete table names + 1="${1/-handle/}" + fi + case $1 in + (arp | bridge | inet | ip | ip6 | netdev) + tables+=( ${(f)"$(_call_program -p nft-tables nft list tables $1 2>/dev/null \ + | cut -d\ -f3 )"} ) + ;; + esac + _describe -V -t tables tables tables "${expl[@]}" +} + +_nft_table_handle(){ + local tables=( ${(f)"$(_call_program -p nft-table-handles nft list ruleset -a 2>/dev/null \ + | grep '^table' | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\3:\2(type \1)/' )"} ) + _describe -t tables tables tables "${expl[@]}" +} + +_nft_obj(){ + #$1:protocol family + #$2:table + #$3:obj type (chain/set/map/flowtable/ct helper/counter/quota/meter) + #$4:include 'handle'? + local objs=( ${(f)"$(_call_program -p nft-$3s nft list table $1 $2 -a 2>/dev/null\ + | grep ""\\s\*$3"" | sed 's/\s*'"$3"' // ;s/ { # \(.*\)/:(\1)/' )"} ) + if $4 ;then + objs+=( "handle:adress chain by handle") + fi + _describe -J -t objs objs objs "${expl[@]}" +} + +_nft_obj_handle(){ + #$1:protocol family + #$2:table + #$3:obj type (chain/set/ct helper/counter/quota) + local handles=( ${(f)"$(_call_program -p nft-$3-handles nft list table $1 $2 -a 2>/dev/null\ + | grep ""\\s\*$3"" | sed 's/\s*'"$3"' // ;s/ { # handle// ;s/\(\S*\) \(\S*\)/\2:\1/' )"} ) + _describe -t handles handles handles "${expl[@]}" +} + +_nft_rule_handle(){ + #$1:protocol family + #$2:table + #$3:chain name + local rules=( ${(f)"$(_call_program -p nft-rule-handles nft list chain $1 $2 $3 -a 2>/dev/null \ + |grep -v '^\s*\(table\|chain\|type\|\}\)'|sed 's/^\s*\(.*\) # handle \(\S*\)$/\2:\1/' )"} ) + _describe -t rules rules rules "${expl[@]}" +} + + +_nft "$@" From 9aaf2e64fb7247939d53237d04bc25e7c3f7919b Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Sun, 4 Nov 2018 15:11:45 +0100 Subject: [PATCH 2/6] Add description/author header --- src/_nft | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/_nft b/src/_nft index cde4d10..d08d9b8 100644 --- a/src/_nft +++ b/src/_nft @@ -1,5 +1,17 @@ #compdef nft - +# ------------------------------------------------------------------------------ +# Description +# ----------- +# +# Completion script for nft 0.9.0 (https://www.netfilter.org/projects/nftables/index.html). +# +# ------------------------------------------------------------------------------ +# Authors +# ------- +# +# * Markus Richter ( https://github.com/mqus , ) +# +# ------------------------------------------------------------------------------ _nft(){ local -a rules states prev args families options descriptors local state="start" line nextstate cmd_obj cmd_subcmd cmd_fam cmd_tab cmd_chain #curcontext="$curcontext" From 0f0b1d818410c8f050b1213a6e17551d8beb9db3 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Sun, 4 Nov 2018 22:42:13 +0100 Subject: [PATCH 3/6] add fixes suggested by okapia and some more --- src/_nft | 72 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/src/_nft b/src/_nft index d08d9b8..7ddf8e1 100644 --- a/src/_nft +++ b/src/_nft @@ -20,21 +20,21 @@ options=( '(-)'{-h,--help}'[show help]' \ '(-)'{-v,--version}'[print version information]' \ "(-i --interactive)"{-i,--interactive}'[read input from interactive CLI]: :->end' \ - "(-f --file)"{-f,--file}'[Read input from ]:nftables rule file:_files' \ - '(-c --check -n --numeric -N)'{-c,--check}'[check commands validity without actually applying the changes]' \ + "(-f --file)"{-f,--file}'[read input from ]:nftables rule file:_files' \ + '(-c --check -n --numeric -N)'{-c,--check}"[check command's validity without actually applying the changes]" \ '(-j --json)'{-j,--json}'[format output in json]' \ - '(-c --check -N)*'{-n,--numeric}'[can be specified up to 3 times, Shows 1:network addresses(default behaviour), 2:Internet services (port numbers) and 3:protocols, user IDs, and group IDs numerically]' \ + '(-c --check -N)*'{-n,--numeric}'[can be specified up to 3 times, Shows 1:network addresses(default behaviour), 2:internet services (port numbers) and 3:protocols, user IDs, and group IDs numerically]' \ '(-s --stateless)'{-s,--stateless}'[omit stateful information of ruleset]' \ '(-N -n --numeric -c --check)'-N'[translate IP addresses to names]' \ '(-a --handle)'{-a,--handle}'[output rule handle]' \ '(-e --echo)'{-e,--echo}'[echo what has been added, inserted or replaced]' \ - {-I,--includepath}'[add to the paths searched for include files. Default is /usr/share]:include directory:_path_files -/' \ + {-I,--includepath}'[add specified directory to the paths searched for include files]:include directory [/usr/share]:include directory:_directories' ) # start a state machine. The state is modified by _arguments if the # current argument (descriptors) cannot be completed. Each state has to define is successive state and the # 'descriptors' for _arguments, which essentially tells _arguments how to complete -_i=0 +local _i=0 while true;do (( _i+=1 )) #Guard for endless loops @@ -167,12 +167,12 @@ while true;do ;; (delete-chain | delete-set | delete-quota | delete-counter | delete-ct\\ helper) cmd_tab=$line[1] - descriptors=(": : _nft_obj $cmd_fam $cmd_tab $cmd_obj true") + descriptors=(": : _nft_object $cmd_fam $cmd_tab $cmd_obj true") nextstate="delete-obj-handle" ;; (delete-obj-handle) if [[ $line[1] == "handle" ]]; then - descriptors=(": : _nft_obj_handle $cmd_fam $cmd_tab $cmd_obj") + descriptors=(": : _nft_object_handle $cmd_fam $cmd_tab $cmd_obj") else descriptors=(": :(\;)") fi @@ -184,12 +184,12 @@ while true;do ;; (rename-chain) cmd_tab=$line[1] - descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + descriptors=(": : _nft_object $cmd_fam $cmd_tab chain false") nextstate="add-chain" ;; (replace-rule | delete-rule) cmd_tab=$line[1] - descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + descriptors=(": : _nft_object $cmd_fam $cmd_tab chain false") nextstate="repdel-rule" ;; (repdel-rule) @@ -203,7 +203,7 @@ while true;do ;; (add-rule) cmd_tab=$line[1] - descriptors=(": : _nft_chain $cmd_fam $cmd_tab false") + descriptors=(": : _nft_object $cmd_fam $cmd_tab chain false") nextstate="add-rule-2" ;; (add-rule-2) @@ -234,7 +234,7 @@ while true;do ;; (list-set | list-map | delete-map | list-chain | list-flowtable | delete-flowtable | list-ct\\ helper | list-counter | list-quota | list-meter) cmd_tab=$line[1] - descriptors=(": : _nft_obj $cmd_fam $cmd_tab $cmd_obj false") + descriptors=(": : _nft_object $cmd_fam $cmd_tab $cmd_obj false") nextstate="start" ;; #TODO: @@ -273,19 +273,19 @@ _nft_subcommands(){ 'monitor:listen to Netlink events' 'describe:show information about the type of an expression and its data type' ) - _describe -t commands 'nft subcommands' commands "${expl[@]}" + _describe -t commands 'nft subcommand' commands "${expl[@]}" } _nft_mon_filter(){ - local filter=( + local monitor_filters=( 'new:show only events of created objects' 'destroy:show only events of deleted objects' ) - _describe -t filter 'nft monitor' filter -J "action filter" "${expl[@]}" + _describe -t monitor_filters 'nft monitor' monitor_filters -J monitor_filters "${expl[@]}" _nft_mon_keywords } _nft_mon_keywords(){ - local objs=( + local monitor_keywords=( 'tables:show table events' 'chains:show chain events' 'sets:show set events' @@ -293,16 +293,16 @@ _nft_mon_keywords(){ 'elements:show only events of element objects' 'ruleset:show ruleset events, such as table, chain, rule, set, counters and quotas' ) - _describe -t objs 'nft monitor' objs -J "object filter" "${expl[@]}" + _describe -t monitor_keywords 'nft monitor' monitor_keywords -J monitor_keywords "${expl[@]}" _nft_out_format } _nft_out_format(){ - local commands=( + local monitor_format=( 'json:format output to JSON' 'xml:format output to XML' ) - _describe -t commands "output format" commands -J "output format options" "${expl[@]}" + _describe -t monitor_format "output format" monitor_format -J monitor_format "${expl[@]}" } _nft_add(){ @@ -418,7 +418,7 @@ _nft_table(){ #$1 can be: all all-handle -handle local tables=() if [[ "$1" =~ "^all" ]]; then - tables+=( ${(f)"$(_call_program -p nft-tables nft list tables 2>/dev/null \ + tables+=( ${(f)"$(_call_program -p tables nft list tables 2>/dev/null \ | cut -d\ -f2 |sort|uniq -u )"} ) 1="${1/all/ip}" fi @@ -429,48 +429,52 @@ _nft_table(){ fi case $1 in (arp | bridge | inet | ip | ip6 | netdev) - tables+=( ${(f)"$(_call_program -p nft-tables nft list tables $1 2>/dev/null \ + tables+=( ${(f)"$(_call_program -p tables nft list tables $1 2>/dev/null \ | cut -d\ -f3 )"} ) ;; esac - _describe -V -t tables tables tables "${expl[@]}" + _describe -V -t tables "table" tables "${expl[@]}" } _nft_table_handle(){ - local tables=( ${(f)"$(_call_program -p nft-table-handles nft list ruleset -a 2>/dev/null \ + local tables=( ${(f)"$(_call_program -p tables nft list ruleset -a 2>/dev/null \ | grep '^table' | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\3:\2(type \1)/' )"} ) - _describe -t tables tables tables "${expl[@]}" + _describe -t tables "table handle" tables "${expl[@]}" } -_nft_obj(){ +_nft_object(){ + # complete the names of objects contained directly in a table (with the handle number in the description) #$1:protocol family #$2:table - #$3:obj type (chain/set/map/flowtable/ct helper/counter/quota/meter) + #$3:object type (chain/set/map/flowtable/ct helper/counter/quota/meter) #$4:include 'handle'? - local objs=( ${(f)"$(_call_program -p nft-$3s nft list table $1 $2 -a 2>/dev/null\ + local objects=( ${(f)"$(_call_program -p objects nft list table $1 $2 -a 2>/dev/null\ | grep ""\\s\*$3"" | sed 's/\s*'"$3"' // ;s/ { # \(.*\)/:(\1)/' )"} ) if $4 ;then - objs+=( "handle:adress chain by handle") + objects+=( "handle:adress $3 by handle") fi - _describe -J -t objs objs objs "${expl[@]}" + _describe -J -t objects "$3" objects "${expl[@]}" } -_nft_obj_handle(){ +_nft_object_handle(){ + # complete handles of objects contained directly in a table (with the name in the description) #$1:protocol family #$2:table - #$3:obj type (chain/set/ct helper/counter/quota) - local handles=( ${(f)"$(_call_program -p nft-$3-handles nft list table $1 $2 -a 2>/dev/null\ + #$3:object type (chain/set/ct helper/counter/quota) + local handles=( ${(f)"$(_call_program -p handles nft list table $1 $2 -a 2>/dev/null\ | grep ""\\s\*$3"" | sed 's/\s*'"$3"' // ;s/ { # handle// ;s/\(\S*\) \(\S*\)/\2:\1/' )"} ) - _describe -t handles handles handles "${expl[@]}" + _describe -t handles "$3-handle" handles "${expl[@]}" } _nft_rule_handle(){ + # complete the handles of rules (and put the rule into the description) #$1:protocol family #$2:table #$3:chain name - local rules=( ${(f)"$(_call_program -p nft-rule-handles nft list chain $1 $2 $3 -a 2>/dev/null \ + local rules=( ${(f)"$(_call_program -p nft-rule-handle nft list chain $1 $2 $3 -a 2>/dev/null \ |grep -v '^\s*\(table\|chain\|type\|\}\)'|sed 's/^\s*\(.*\) # handle \(\S*\)$/\2:\1/' )"} ) - _describe -t rules rules rules "${expl[@]}" + # don't sort those entries alphabetically, so they get shown in the order they are executed in nftables + _describe -t rules "rule" rules -V "rules" "${expl[@]}" } From ecd02cf5baaa918225a0493f45e7e4eee15e128b Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Mon, 5 Nov 2018 14:53:29 +0100 Subject: [PATCH 4/6] renamed file, documented some more functions --- src/{_nft => _nftables} | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) rename src/{_nft => _nftables} (98%) diff --git a/src/_nft b/src/_nftables similarity index 98% rename from src/_nft rename to src/_nftables index 7ddf8e1..a350e00 100644 --- a/src/_nft +++ b/src/_nftables @@ -415,6 +415,7 @@ _nft_families(){ } _nft_table(){ + # complete the names of tables and the families of existing tables #$1 can be: all all-handle -handle local tables=() if [[ "$1" =~ "^all" ]]; then @@ -437,6 +438,7 @@ _nft_table(){ } _nft_table_handle(){ + # complete the handles of tables (with the table name in the description) local tables=( ${(f)"$(_call_program -p tables nft list ruleset -a 2>/dev/null \ | grep '^table' | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\3:\2(type \1)/' )"} ) _describe -t tables "table handle" tables "${expl[@]}" @@ -477,5 +479,5 @@ _nft_rule_handle(){ _describe -t rules "rule" rules -V "rules" "${expl[@]}" } - +#currently, only the `nft` command is covered by this script. _nft "$@" From 6eda4d827697634de444c0c93da817aa5d5a76f7 Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Tue, 6 Nov 2018 00:53:51 +0100 Subject: [PATCH 5/6] fix family/handle/table completion, remove uneccessary expl --- src/_nftables | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/_nftables b/src/_nftables index a350e00..d6e1381 100644 --- a/src/_nftables +++ b/src/_nftables @@ -130,6 +130,10 @@ while true;do descriptors=(": : _nft_table ${line[1]}-handle") cmd_fam=$line[1] ;; + # if 'handle' was completed, complete the handle number. + (handle) + descriptors=(": : _nft_table_handle_all " ) + ;; # else, complete nothing and go to the next state. default family is 'ip' (*) descriptors=() @@ -158,6 +162,7 @@ while true;do nextstate="start" ;; (delete-table) + #if family AND handle were input, complete handle number for given family. if [[ $line[1] == "handle" ]]; then descriptors=(":table handle: _nft_table_handle $cmd_fam" ) else @@ -403,7 +408,7 @@ _nft_reset(){ _describe -t commands 'nft reset' commands "$@" } _nft_families(){ - local commands=( + local families=( "ip:IPv4 address family" "ip6:IPv6 address family" "inet:internet (IPv4+IPv6) address family" @@ -411,7 +416,7 @@ _nft_families(){ "bridge:Bridge address family, handling packets which traverse a bridge device" "netdev:Netdev address family, handling packets from ingress" ) - _describe -t commands 'nft families' commands "$@" + _describe -t families 'nft families' families "$@" } _nft_table(){ @@ -419,29 +424,41 @@ _nft_table(){ #$1 can be: all all-handle -handle local tables=() if [[ "$1" =~ "^all" ]]; then - tables+=( ${(f)"$(_call_program -p tables nft list tables 2>/dev/null \ - | cut -d\ -f2 |sort|uniq -u )"} ) + local families=( ${(f)"$(_call_program -p tables nft list tables 2>/dev/null \ + | cut -d\ -f2 )"} ) + # ip is the default family, search also for table names there 1="${1/all/ip}" + _describe -t families "family" families -J "family" fi if [[ "$1" =~ "-handle$" ]]; then - tables+=("handle") + tables=("handle:adress the table by handle") #remove -handle from $1 to be able to complete table names 1="${1/-handle/}" + _describe -t tables "table" tables -V "handle" fi case $1 in (arp | bridge | inet | ip | ip6 | netdev) - tables+=( ${(f)"$(_call_program -p tables nft list tables $1 2>/dev/null \ - | cut -d\ -f3 )"} ) + tables=( ${(f)"$(_call_program -p tables nft list ruleset -a 2>/dev/null \ + | grep '^table '"$1" | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\2:type \1, handle \3/' )"} ) + _describe -t tables "table" tables -V "table-name" ;; esac - _describe -V -t tables "table" tables "${expl[@]}" } _nft_table_handle(){ - # complete the handles of tables (with the table name in the description) + # complete the handles of tables with the specified family (with the table name in the description) + #$1:protocol family + local tables=( ${(f)"$(_call_program -p tables nft list ruleset -a 2>/dev/null \ + | grep '^table '"$1" | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\3:\2(type \1)/' )"} ) + echo $1 > /tmp/znfttab + _describe -t tables "table handle" tables +} + +_nft_table_handle_all(){ + # complete the handles of tables of all families (with the table name in the description) local tables=( ${(f)"$(_call_program -p tables nft list ruleset -a 2>/dev/null \ | grep '^table' | sed 's/table // ;s/{ # handle // ;s/\(\S*\) \(\S*\) \(\S*\)/\3:\2(type \1)/' )"} ) - _describe -t tables "table handle" tables "${expl[@]}" + _describe -t tables "table handle" tables } _nft_object(){ @@ -455,7 +472,7 @@ _nft_object(){ if $4 ;then objects+=( "handle:adress $3 by handle") fi - _describe -J -t objects "$3" objects "${expl[@]}" + _describe -t objects "$3" objects } _nft_object_handle(){ @@ -465,7 +482,7 @@ _nft_object_handle(){ #$3:object type (chain/set/ct helper/counter/quota) local handles=( ${(f)"$(_call_program -p handles nft list table $1 $2 -a 2>/dev/null\ | grep ""\\s\*$3"" | sed 's/\s*'"$3"' // ;s/ { # handle// ;s/\(\S*\) \(\S*\)/\2:\1/' )"} ) - _describe -t handles "$3-handle" handles "${expl[@]}" + _describe -t handles "$3-handle" handles } _nft_rule_handle(){ @@ -476,7 +493,7 @@ _nft_rule_handle(){ local rules=( ${(f)"$(_call_program -p nft-rule-handle nft list chain $1 $2 $3 -a 2>/dev/null \ |grep -v '^\s*\(table\|chain\|type\|\}\)'|sed 's/^\s*\(.*\) # handle \(\S*\)$/\2:\1/' )"} ) # don't sort those entries alphabetically, so they get shown in the order they are executed in nftables - _describe -t rules "rule" rules -V "rules" "${expl[@]}" + _describe -t rules "rule" rules -V "rules" } #currently, only the `nft` command is covered by this script. From 28679cf7c330d2313a1e1c472b712527e4dc00bd Mon Sep 17 00:00:00 2001 From: Markus Richter <8398165+mqus@users.noreply.github.com> Date: Tue, 6 Nov 2018 20:56:19 +0100 Subject: [PATCH 6/6] remove last expl[@] strings and replace them with the generic "$@" --- src/_nftables | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_nftables b/src/_nftables index d6e1381..32159b5 100644 --- a/src/_nftables +++ b/src/_nftables @@ -278,14 +278,14 @@ _nft_subcommands(){ 'monitor:listen to Netlink events' 'describe:show information about the type of an expression and its data type' ) - _describe -t commands 'nft subcommand' commands "${expl[@]}" + _describe -t commands 'nft subcommand' commands "$@" } _nft_mon_filter(){ local monitor_filters=( 'new:show only events of created objects' 'destroy:show only events of deleted objects' ) - _describe -t monitor_filters 'nft monitor' monitor_filters -J monitor_filters "${expl[@]}" + _describe -t monitor_filters 'nft monitor' monitor_filters -J monitor_filters "$@" _nft_mon_keywords } @@ -298,7 +298,7 @@ _nft_mon_keywords(){ 'elements:show only events of element objects' 'ruleset:show ruleset events, such as table, chain, rule, set, counters and quotas' ) - _describe -t monitor_keywords 'nft monitor' monitor_keywords -J monitor_keywords "${expl[@]}" + _describe -t monitor_keywords 'nft monitor' monitor_keywords -J monitor_keywords "$@" _nft_out_format } @@ -307,7 +307,7 @@ _nft_out_format(){ 'json:format output to JSON' 'xml:format output to XML' ) - _describe -t monitor_format "output format" monitor_format -J monitor_format "${expl[@]}" + _describe -t monitor_format "output format" monitor_format -J monitor_format "$@" } _nft_add(){