1#compdef swanctl 2 3# Completion for strongSwan's swanctl. See also ipsec, which is deprecated but 4# still supported by strongSwan, and also used by Openswan/Libreswan. 5# 6# Note that in most cases elevated privileges are required to connect to the 7# VICI socket, so the gain-privileges style may be necessary to complete SA 8# names and the like: zstyle ':completion:*:swanctl/*' gain-privileges yes 9# 10# Other notes: 11# - One of swanctl's selling points is that it can provide 'raw' structured 12# responses for scripting, etc. In practice, though, the output formatted for 13# humans seems easier to 'parse' from the shell than the plist-like raw output 14# - @todo We don't complete authority names, pool names, peer IPs, etc. 15 16# Complete connection names, SA names, or SA unique IDs. The distinctions 17# between concepts like 'connections' and 'SAs' are very blurry here, partially 18# for convenience and partially due to author confusion 19# --child => complete only child/CHILD_SA names/IDs 20# --ids => complete unique SA IDs rather than connection/SA names 21# --ike => complete only connection/IKE_SA names/IDs 22(( $+functions[_swanctl_connections] )) || 23_swanctl_connections() { 24 local i which 25 local -a expl tmp matches 26 local -A opts 27 28 zparseopts -D -E -A opts - -child -ids -ike 29 30 tmp=( ${(@M)${(f)"$( 31 _call_program -p swanctl-sas $words[1] -l 32 )"}:#[^:]##: \#<->*} ) 33 (( $+opts[--ids] )) || tmp+=( ${(@M)${(f)"$( 34 _call_program -p swanctl-conns $words[1] -L 35 )"}:#[^:]##: ([A-Z][A-Za-z0-9]#|),*} ) 36 37 for i in $tmp; do 38 if (( $+opts[--child] )) && [[ $i != [[:space:]]* ]]; then 39 continue 40 elif (( $+opts[--ike] )) && [[ $i == [[:space:]]* ]]; then 41 continue 42 fi 43 44 # <name>: #<unique id>, ... 45 i=${i//[#:,]/ } 46 47 if (( $+opts[--ids] )); then 48 matches+=( "${i[(w)2]}:${i[(w)1]} #${i[(w)2]}" ) 49 else 50 matches+=( ${i[(w)1]} ) 51 fi 52 done 53 54 if (( $+opts[--ids] )); then 55 matches=( ${(onu)matches} ) 56 if (( $+opts[--child] )); then 57 which=CHILD_ 58 elif (( $+opts[--ike] )); then 59 which=IKE_ 60 fi 61 _describe -x2Vt sa-ids "${which}SA unique ID" matches 62 else 63 if (( $+opts[--child] )); then 64 which='child ' 65 elif (( $+opts[--ike] )); then 66 which='IKE ' 67 fi 68 _wanted -x connections expl "${which}connection/SA name" compadd - $matches 69 fi 70} 71 72_swanctl() { 73 # Although swanctl will correctly parse multiple short options in the first 74 # word, as in `swanctl -lh`, it won't actually *do* anything with the 75 # subsequent options -- so we'll require that they be separated. Also, --help 76 # doesn't take any further options, so just stop if we've got that 77 if (( CURRENT == 2 )) || [[ $words[2] == (-h*|--help) ]]; then 78 _arguments : \ 79 '(-)'{-a,--load-pools}'[(re)load pool configuration]' \ 80 '(-)'{-A,--list-pools}'[display loaded pool configurations]' \ 81 '(-)'{-b,--load-authorities}'[(re)load authority configuration]' \ 82 '(-)'{-B,--list-authorities}'[display loaded authority configurations]' \ 83 '(-)'{-c,--load-conns}'[(re)load connection configuration]' \ 84 '(-)'{-C,--counters}'[display or reset IKE event counters]' \ 85 '(-)'{-d,--redirect}'[redirect IKE_SA]' \ 86 '(-)'{-f,--flush-certs}'[flush cached certificates]' \ 87 '(-)'{-g,--list-algs}'[display loaded algorithms]' \ 88 '(-)'{-h,--help}'[display help information]' \ 89 '(-)'{-i,--initiate}'[initiate a connection]' \ 90 '(-)'{-l,--list-sas}'[display currently active IKE_SAs]' \ 91 '(-)'{-L,--list-conns}'[display loaded configurations]' \ 92 '(-)'{-m,--monitor-sa}'[monitor for IKE_SA and CHILD_SA changes]' \ 93 '(-)'{-p,--install}'[install trap or shunt policy]' \ 94 '(-)'{-P,--list-pols}'[display currently installed policies]' \ 95 '(-)'{-q,--load-all}'[load credentials, authorities, pools, and connections]' \ 96 '(-)'{-r,--reload-settings}'[reload daemon strongswan.conf]' \ 97 '(-)'{-R,--rekey}'[rekey SA]' \ 98 '(-)'{-s,--load-creds}'[(re)load credentials]' \ 99 '(-)'{-S,--stats}'[display daemon statistics]' \ 100 '(-)'{-t,--terminate}'[terminate connection]' \ 101 '(-)'{-T,--log}'[trace logging output]' \ 102 '(-)'{-u,--uninstall}'[uninstall trap or shunt policy]' \ 103 '(-)'{-v,--version}'[display version information]' \ 104 '(-)'{-x,--list-certs}'[display stored certificates]' 105 return 106 fi 107 108 local ret=1 cmd 109 local -a args cert_flags cert_types 110 111 cert_flags=( aa any ca none ocsp ) 112 cert_types=( ocsp_response pubkey x509 x509_ac x509_crl ) 113 114 if [[ $words[2] == -[^-]* ]]; then 115 cmd=${(M)words[2]#??} 116 else 117 cmd=$words[2] 118 fi 119 words=( $words[1] "${(@)words[3,-1]}" ) 120 (( CURRENT-- )) 121 122 # Technically, only -v, -u, and -+ are truly global command options. However, 123 # in practice, all commands also support -h, -P, and -r 124 args=( 125 '(: * -)'{-h,--help}'[display help information]' 126 '(-P -r --pretty --raw)'{-P,--pretty}'[dump raw response message in pretty print]' 127 '(-P -r --pretty --raw)'{-r,--raw}'[dump raw response message]' 128 # https://wiki.strongswan.org/projects/strongswan/wiki/LoggerConfiguration 129 # https://github.com/strongswan/strongswan/blob/master/src/libstrongswan/utils/debug.h 130 '(-v --debug)'{-v+,--debug=}'[specify debug level]:debug level [1]:(( 131 -1\:"absolutely silent (SILENT)" 132 0\:"basic auditing (AUDIT)" 133 1\:"generic control flow with errors (CTRL)" 134 2\:"detailed control flow (DIAG)" 135 3\:"raw binary blobs (RAW)" 136 4\:"sensitive data (PRIVATE)" 137 ))' 138 '(-u --uri)'{-u+,--uri=}'[specify service URI to connect to]:VICI service URI:_urls' 139 '(-+ --options)'{'-\++',--options=}'[read command-line options from specified file]:options file:_files' 140 ) 141 142 case $cmd in 143 -A|--list-pools) args+=( 144 '(-n --name)'{-n+,--name=}'[filter by specified pool name]:pool name' 145 '(-l --leases)'{-l,--leases}'[display leases of each pool]' 146 ) ;; 147 -B|--list-authorities) args+=( 148 '(-n --name)'{-n+,--name=}'[filter by specified authority name]:authority name' 149 ) ;; 150 -C|--counters) args+=( 151 '(-a -n --all --name)'{-a,--all}'[display/reset counters for all tracked connections]' 152 '(-a -n --all --name)'{-n+,--name=}'[specify connection name]: :_swanctl_connections --ike' 153 '(-r --reset)'{-r,--reset}'[reset counters]' 154 ) ;; 155 -d|--redirect) args+=( 156 '(-d --peer-id)'{-d+,--peer-id=}'[redirect by IKE_SA matching specified peer identity]:peer identity' 157 '(-g --gateway)'{-g+,--gateway=}'[redirect to specified gateway]:target gateway' 158 '(-i --ike)'{-i+,--ike=}'[redirect by specified IKE_SA name]: :_swanctl_connections --ike' 159 '(-I --ike-id)'{-I+,--ike-id=}'[redirect by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike' 160 '(-p --peer-ip)'{-p+,--peer-ip=}'[redirect by IKE_SA matching specified peer IP]:peer IP address' 161 ) ;; 162 -f|--flush-certs) args+=( 163 '(-t --type)'{-t+,--type=}"[filter by specified certificate type]:certificate type:( 164 ${(j< >)${(@q-)cert_types}} 165 )" 166 ) ;; 167 -i|--initiate) args+=( 168 '(-c --child)'{-c+,--child=}'[specify CHILD_SA name]: :_swanctl_connections --child' 169 '(-i --ike)'{-i+,--ike=}"[specify CHILD_SA's connection name]: :_swanctl_connections --ike" 170 '(-t --timeout)'{-t+,--timeout=}'[specify timeout before detaching]:timeout (seconds)' 171 ) ;; 172 -l|--list-sas) args+=( 173 '(-i --ike)'{-i+,--ike=}'[filter by specified IKE_SA name]: :_swanctl_connections --ike' 174 '(-I --ike-id)'{-I+,--ike-id=}'[filter by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike' 175 '(-n --noblock)'{-n,--noblock}'[do not wait for IKE_SAs in use]' 176 ) ;; 177 -p|-u|--install|--uninstall) args+=( 178 '(-c --child)'{-c+,--child=}'[specify CHILD_SA name]: :_swanctl_connections --child' 179 '(-i --ike)'{-i+,--ike=}"[specify CHILD_SA's connection name]: :_swanctl_connections --ike" 180 ) ;; 181 -P|--list-pols) args+=( 182 '(-c --child)'{-c+,--child=}'[filter by specified CHILD_SA name]: :_swanctl_connections --child' 183 '(-d --drop)'{-d,--drop}'[list drop policies]' 184 '(-p --pass)'{-p,--pass}'[list bypass policies]' 185 '(-t --trap)'{-t,--trap}'[list trap policies]' 186 ) ;; 187 -q|-s|--load-all|--load-creds) args+=( 188 '(-c --clear)'{-c,--clear}'[clear previously loaded credentials]' 189 '(-n --noprompt)'{-n,--noprompt}'[do not prompt for passwords]' 190 ) ;; 191 -R|--rekey) args+=( 192 '(-c --child)'{-c+,--child=}'[rekey by specified CHILD_SA name]: :_swanctl_connections --child' 193 '(-C --child-id)'{-C+,--child-id=}'[rekey by specified CHILD_SA unique ID]: :_swanctl_connections --ids --child' 194 '(-i --ike)'{-i+,--ike=}'[rekey by specified IKE_SA name]: :_swanctl_connections --ike' 195 '(-I --ike-id)'{-I+,--ike-id=}'[rekey by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike' 196 ) ;; 197 -t|--terminate) args+=( 198 '(-t --timeout)'{-t+,--timeout=}'[specify timeout before detaching]:timeout (seconds)' 199 '(-c --child)'{-c+,--child=}'[terminate by specified CHILD_SA name]: :_swanctl_connections --child' 200 '(-C --child-id)'{-C+,--child-id=}'[terminate by specified CHILD_SA unique ID]: :_swanctl_connections --ids --child' 201 '(-i --ike)'{-i+,--ike=}'[terminate by specified IKE_SA name]: :_swanctl_connections --ike' 202 '(-I --ike-id)'{-I+,--ike-id=}'[terminate by specified IKE_SA unique ID]: :_swanctl_connections --ids --ike' 203 ) ;; 204 -v|--version) args+=( 205 '(-d --daemon)'{-d,--daemon}'[query daemon version]' 206 ) ;; 207 -x|--list-certs) args+=( 208 '(-f --flag)'{-f+,--flag=}"[filter by specified X.509 certificate flag]:certificate flag:( 209 ${(j< >)${(@q-)cert_flags}} 210 )" 211 '(-p --pem)'{-p,--pem}'[display PEM encoding of certificate]' 212 '(-s --subject)'{-s+,--subject=}'[filter by specified certificate subject]:certificate subject' 213 '(-S --short)'{-S,--short}'[omit some certificate details]' 214 '(-t --type)'{-t+,--type=}"[filter by specified certificate type]:certificate type:( 215 ${(j< >)${(@q-)cert_types}} 216 )" 217 '(-u --utc)'{-u,--utc}'[use UTC for time fields]' 218 ) ;; 219 esac 220 221 _arguments -s -S : $args && ret=0 222 return ret 223} 224 225_swanctl "$@" 226