1#compdef netstat
2
3local Wopt Xopt nopt="[don't resolve addresses to names]"
4local lopt='[show only listening sockets]'
5local zopt='-z[reset statistic counters after displaying them]'
6local popt='(-f)-p+[filter by protocol]:protocol:compadd -a plist'
7local Iopt='(-i)-I+[show information about the specified interface]:interface:_net_interfaces'
8local set sel
9local -A sets
10local -a Mopts families flist plist args sockets extend interval verbose
11local -a {sel_,}{bpf,dhcp,groups,interfaces,masquerade,media,memory,multicast,pcb,queues,routing,statistics,wireless}
12
13case $OSTYPE in
14  linux-gnu)
15    families=(
16      '(-4 --inet)'{-4,--inet}
17      '(-6 --inet)'{-4,--inet6}
18      '(-A --protocol)'{-A+,--protocol=}':protocol:_sequence compadd - inet inet6 unix ipx ax25 netrom ddp bluetooth'
19      --unix -x --ip --tcpip --ax25 --x25 --rose --ash
20      --bluetooth --ipx --netrom --ddp --appletalk --econet --ec
21    )
22    extend=( \*{-e,--extend}'[show additional information]' )
23    verbose=( '(-v --verbose)'{-v,--verbose}'[show what is going on]' )
24    args=(
25      '(-c --continuous)'{-c,--continuous}'[repeat information every second]'
26      '!(-n --numeric)'{-N,--symbolic}
27      '(-n --numeric)'{-n,--numeric}"$nopt"
28      --numeric-hosts --numeric-ports --numeric-users
29      '1: :_guard "[0-9]#" "repeat interval (seconds)"'
30      - '(help)'
31      '(- 1)'{-h,--help}'[display usage information]'
32      '(- 1)'{-V,--version}'[display version information]'
33    )
34    sets=(
35      routing    '(--route|-[^-]#r*)'
36      groups     '(--groups|-[^-]#g*)'
37      interfaces '(--interfaces|-[^-]#[iI]*)'
38      statistics '(--statistics|-[^-]#s*)'
39      masquerade '(--masquerade|-[^-]#M*)'
40    )
41
42    sel_routing=( '(-r --route)'{-r,--route}'[display routing table]' )
43    sel_interfaces=(
44      '(-I --interfaces)-i[display interface table]'
45      '(-i -I --interfaces)'{--interface=-,-I=-}'[display interface table]::interface:_net_interfaces'
46    )
47    sel_groups=( '(-g --groups)'{-g,--groups}'[display multicast group memberships]' )
48    sel_masquerade=( '(-M --masquerade)'{-M,--masquerade}'[display masqueraded connections]' )
49    [[ -e /proc/net/ip_masquerade ]] || sel_masquerade=( \!${^sel_masquerade} )
50    sel_statistics=( '(-s --statistics -c --continuous -n --numeric --numeric-hosts --numeric-ports --numeric-users)'{-s,--statistics}'[display networking statistics]' )
51
52    sockets=(
53      $families $verbose
54      --tcp -t --udp -u --udplite -U --sctp -S --raw -w
55      '(-2 --l2cap)'{-2,--l2cap}
56      '(-f --rfcomm)'{-f,--rfcomm}
57      '(-a --all -l --listening)'{-l,--listening}$lopt
58      '(-a --all -l --listening)'{-a,--all}'[show all sockets]'
59      --symbolic -N --extend -e
60      '(--timers -o)'{--timers,-o}'[show information on networking timers]'
61      '(--program -p)'{--program,-p}'[show process id and program name for sockets]'
62      '(--wide -W)'{--wide,-W}"[don't truncate IP addresses in output]"
63      '(-Z --context)'{-Z,--context}'[display SELinux security context for sockets]'
64    )
65    routing=(
66      $families $extend $verbose
67      '-C[display routing cache instead of FIB]'
68    )
69    interfaces=(
70      $extend $verbose
71      '(-a --all)'{-a,--all}'[show interfaces that are not up]'
72    )
73    groups=()
74    masquerade=( $extend )
75    statistics=( $families )
76  ;;
77  solaris*|darwin*|dragonfly*|freebsd*)
78    families=( '(-p -4 -6)-f+[specify address family]:address family:compadd -a flist' )
79  ;|
80  freebsd*)
81    families+=(
82      '(-6 -f)-4[show IPv4 only]'
83      '(-4 -f)-6[show IPv6 only]'
84    )
85  ;|
86  (open|net)bsd*)
87    popt='(-f)-p+[filter by protocol]:protocol:compadd - ${(M)${(f)"$(</etc/protocols)"}##[a-z0-9]#}'
88    families=(
89      '(-u)-f+[specify address family]:address family:_sequence compadd - -a flist'
90      '(-f)-u[limit reports to the unix address family]' # undocumented on NetBSD
91    )
92  ;|
93  *) # everything except linux
94    sets=(
95      routing    '-[^-]#r*'
96      groups     '-[^-]#g*'
97      interfaces '-[^-]#[iIw]*'
98      memory     '-[^-]#m*'
99      statistics '-[^-]#s*'
100    )
101    flist=( inet inet6 unix )
102    verbose=( '-v[verbose]' )
103    sel_routing=( '-r[display routing table]' )
104    sel_groups=( '-g[display multicast group memberships]' )
105    sel_interfaces=( $Iopt '-i[display interface table]' )
106    sel_statistics=( '*-s[display per protocol statistics]' )
107    sockets=( $families -n$nopt '-a[show all sockets]' )
108    routing=( -n$nopt )
109    interfaces=( $families -n$nopt )
110    statistics=( $families )
111  ;|
112  (open|net)bsd*)
113    sets+=( pcb '-[^-]#P*' )
114    sel_pcb=( '-P+[display contents of the protocol control block]:pcb' )
115    routing+=( $verbose '(-L)-s[show routing statistics]' )
116    groups+=( $families
117      '(-s)-l[display wider fields for the IPv6 multicast routing table]'
118      '(-l)-s[show multicast routing statistics]'
119    )
120    interfaces+=(
121      '(-p)-s[show interface statistics]'
122    )
123  ;|
124  darwin*|dragonfly*|(net|free|open)bsd*)
125    sockets+=( '-A[show address of a PCB associated with sockets]' )
126    interfaces+=(
127      '-b[show the number of bytes in and out]'
128      '-d[show the number of dropped packets]'
129      '1: :_guard "[0-9]#" "repeat interval (seconds)"'
130    )
131    routing=( $families )
132    sel_memory=( '-m[display statistics recorded by the memory management routines]' )
133    sel_interfaces+=( '(1 -a -f -i -p -s)-w+[display packet traffic at intervals]:interval (seconds)' )
134  ;|
135  darwin*|dragonfly*|(net|free)bsd*)
136    interfaces+=( '-a[show multicast addresses currently in use]' )
137  ;|
138  dragonfly*|(net|free|open)bsd*)
139    Mopts=(
140      '-M+[extract values from specified core]:core file:_files'
141      '-N+[extract name list from specified system image]:system image:_files'
142    )
143    interfaces+=(
144      '-h[print all counters in human readable form]'
145    )
146    sockets+=( $Mopts )
147  ;|
148  darwin*|dragonfly*|freebsd*)
149    Wopt='-W+[avoid truncating fields even if it causes overflow]'
150    sockets+=( $Wopt
151      '-L[show size of listen queues]'
152    )
153    groups+=( $Wopt )
154  ;|
155  dragonfly*|netbsd*|freebsd*)
156    sockets+=( '(-n)-S[show network addresses as numbers but show ports symbolically]' )
157  ;|
158  netbsd*|freebsd*)
159    sets+=( bpf '-[^-]#B*' )
160    sel_bpf=( '-B[display statistics about bpf(4) peers]' )
161  ;|
162  dragonfly*|freebsd*)
163    plist=( divert icmp igmp ip ipsec pim tcp udp icmp6 ip6 rip6 tcp udp pfkey ctrl data )
164    sockets+=( $popt )
165    statistics+=( $popt $zopt $Mopts )
166    memory+=( $Mopts )
167    routing+=( $Mopts $zopt
168      '(-A -a -f -l -n -W)*-s[show routing statistics]'
169      '-W[show path MTU for each route]'
170    )
171    groups+=( $families $Mopts
172    '(-W)*-s[show multicast routing statistics; repeat to suppress those with zero counters]'
173    )
174  ;|
175
176  solaris2.<11->)
177    sets+=( dcache '-[^-]#d*' )
178    sel_dcache=( '-d[display the destination cache entry table]' )
179    dcache=( $families )
180    args=( '-T+[specify time format]:time format:((u\:seconds\ since\ epoch d\:standard\ date\ format))' )
181    sockets+=(
182      '-u[list user, pid and program that created network endpoint]'
183      '-k[show only sockets with kernel data path bypass enabled]'
184      '-L[only show state of sockets using SO_REUSEPORT load balancing]'
185    )
186  ;&
187  solaris*)
188    args=( -A '-*' $args )
189    interval=(
190      '1: :_guard "[0-9]#" "repeat interval (seconds)"'
191      '2: :_guard "[0-9]#" "count"'
192    )
193    sets+=(
194      dhcp      '-[^-]#D*'
195      media     '-[^-]#p*'
196      multicast '-[^-]#M*'
197    )
198    sel_media=( '-p[display net to media tables]' )
199    sel_memory=( '-m[display STREAMS memory statistics]' )
200    sel_multicast=( '-M[display multicast routing tables]' )
201    sel_dhcp=( '-D[display status of DHCP configured interfaces]' )
202    sockets+=(
203      $verbose
204      '-R[show extended security attributes]'
205      '-P[specify protocol]:protocol:(ip ipv6 icmp icmpv6 igmp udp tcp rawip)'
206    )
207    routing+=( $verbose
208      '*-f+[filter routing table]:rule:_values -S \: "filter rule" $flist
209	"af[specify address family]\:family\:(inet inet6 unix)"
210        "outif[specify output interface]\:interface\:_net_interfaces"
211        "dst[specify destination IP]\:IP address"
212        "flags[select routes tagged with flags]\:flags"' \
213      '-a[show state of all routing tables]'
214      '-R[show extended security attributes]'
215    )
216    groups+=( $families -n$nopt $verbose )
217    interfaces+=( $interval
218      '-a[show state of all interfaces]'
219    )
220    statistics+=(
221      '-P[specify protocol]:protocol:(ip ipv6 icmp icmpv6 igmp udp tcp rawip)'
222    )
223    media=( -n$nopt $families )
224    memory+=( $verbose $interval )
225    multicast+=(
226      -n$nopt $families
227      '-s[show per protocol statistics]'
228    )
229    dhcp=( $families $Iopt )
230  ;;
231  darwin*)
232    sets+=( queues '-[^-]#q*' )
233    sel_queues=( '*-q[display network interface send queue statistics]' )
234    sel_memory=( \*$sel_memory )
235    sockets+=(
236      '-l[show full IPv6 address]'
237      '-W[avoid truncating addresses]'
238    )
239    routing+=( '-l[show mtu and use wider display]' )
240    interfaces+=(
241      '(-x)-R[show reachability information]'
242      '-S[show interface link status and state]'
243      '(-R)-x[show extended reachability information]'
244    )
245    queues=( $Iopt
246      '-c+[limit statistics to specified queue]:queue'
247    )
248    groups+=( $families
249      '*-v[show link-layer memberships; repeat for timers and counters]'
250    )
251  ;;
252  dragonfly*)
253    plist+=( carp )
254    sockets+=(
255      '-P[show additional protocol-specific information]'
256      '-c+[access cpu specific route table]:cpu'
257    )
258    interfaces+=( $zopt
259      '-B[show maximum buffer sizes instead of current buffer usage]'
260      '-t[show the contents of watchdog timers]'
261      '(-a -B -b -d -h -n -t -w)*-s[show protocol statistics; repeat to suppress those with zero counters]'
262    )
263    routing+=(
264      '-A[show contents of internal Patricia tree structures]'
265      '-a[show protocol-cloned routes]'
266    )
267  ;;
268  openbsd*)
269    sets+=( wireless '-W*' )
270    sel_wireless=( '-W+[display per-interface IEEE 802.11 wireless statistics]:interface' )
271    flist+=( local mpls )
272    sockets+=( -l$lopt '-B[show buffer sizes for TCP sockets]' )
273    routing+=(
274      '-F[only show routes with gateway in the same address family as the destination]'
275      '-T+[select an alternate routing table to query]:routing table'
276    )
277    interfaces+=(
278      '-c+[show specified number of updates, then exit]:count'
279      '-e[show only the number of errors on the interface]'
280      '-q[only show interfaces that have seen packets]'
281      '-t[show current value of the watchdog timer function]'
282    )
283    statistics+=( $popt )
284    pcb+=( $Mopts $verbose )
285  ;;
286  netbsd*)
287    popt='(-f)-p+[filter by protocol]:protocol:compadd - ${(M)${(f)"$(</etc/protocols)"}##[a-z0-9]#}'
288    Xopt='-X[force use of sysctl(3) when retrieving information]'
289    flist+=( arp ns atalk mpls local )
290    sets+=( queues '-[^-]#q*' )
291    sel_queues=( '-q[display software interrupt queue details for all protocols]' )
292    routing+=( $Xopt
293      "(-s)-L[don't show link-level routes]"
294      '-T[show MPLS tags for the routing tables]'
295    )
296    bpf+=( $Xopt $Iopt
297      '-s[show bpf(4) statistics]'
298    )
299    interfaces+=( $Xopt )
300    memory+=( $Xopt) statistics+=( $Xopt )
301    pcb+=( $Mopts $popt )
302  ;;
303  freebsd<11->.*)
304    routing+=( '-F+[show specified routing table]:routing table' )
305    bpf=( '-z[reset statistic counters after displaying them]' )
306    statistics+=( $bpf[-1] )
307  ;&
308  freebsd*)
309    flist+=( pfkey netgraph ng link )
310    plist+=( sctp ipsec6 pfkey )
311
312    sets+=( netisr  '-[^-]#Q*' )
313    sel_netisr=( '-Q[display netisr(9) statistics]' )
314    sockets+=(
315      '-R[show flowid and flowtype for each socket]'
316      '-T[show diagnostic information from the TCP control block]'
317      '-x[show socket buffer and TCP timer statistics]'
318    )
319    interfaces+=(
320      $popt $Mopts $Iopt $Wopt
321      '-q+[exit after specified number of outputs]:number'
322    )
323    bpf+=( $Iopt $zopt )
324  ;;
325esac
326
327# Ignore display specific options except the default (socket) display until a
328# display has been selected. This is not strictly correct (options can be in
329# any order) but makes the completion much more useful. Descriptions for
330# options that select a specific display (option set) typically start with
331# "display" to set them apart from other options.
332sock=''
333for set in ${(k)sets}; do
334  sel=sel_$set
335  if [[ -z $words[(r)$~sets[$set]] ]]; then
336    ign='!'
337  else
338    sock='!'
339    ign=''
340  fi
341  args+=( - "$set" ${(P)sel} ${ign}${(P)^set} )
342done
343args+=( - sockets ${sock}${sockets} )
344
345_arguments -s -S $args
346