eibgrad

importvpncl.sh

Aug 13th, 2022 (edited)
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 15.95 KB | None | 0 0
  1. #!/bin/sh
  2. #DEBUG=; set -x # comment/uncomment to disable/enable debug mode
  3.  
  4. #         name: importvpncl.sh
  5. #      version: 0.6.1 beta, 15-sep-2024, by eibgrad and egc
  6. #      changes: added tls-crypt-v2
  7. #      purpose: configure openvpn client from imported config file
  8. #  script type: standalone
  9. #    1. enable jffs2 (administration->jffs2)
  10. #    2. use shell (telnet/ssh) to execute one of the following commands:
  11. #         curl -kLs bit.ly/ddwrt-installer|tr -d '\r'|sh -s 2gg5ZdRY
  12. #       or
  13. #         wget -qO - bit.ly/ddwrt-installer|tr -d '\r'|sh -s 2gg5ZdRY
  14. #  limitations:
  15. #    - requires dd-wrt build 49838 or later
  16.  
  17. LOG="$([ ${DEBUG+x} ] && \
  18.    echo /tmp/$(basename $0 .${0##*.})_$(date +'%Y-%m-%d-%H%M%S')_$$.log || \
  19.    echo /dev/null)"
  20.  
  21. # function usage()
  22. usage() {
  23.     echo 'Usage: importvpncl.sh [options] [config-file]'
  24.     echo
  25.     echo '  Configure OpenVPN client from imported config file.'
  26.     echo
  27.     echo '  Options:'
  28.     echo '    --nocommit  do NOT issue nvram commit after changes'
  29.     echo '    -h,--help   this usage information'
  30.     echo
  31.     echo '  # e.g., configure from specified config file'
  32.     echo '  importvpncl.sh /tmp/vpnupload.conf'
  33.     echo
  34.     echo '  # e.g., configure from default config file (/tmp/vpnupload.conf)'
  35.     echo '  importvpncl.sh'
  36.     echo
  37.     echo '  # e.g., reset openvpn client to defaults'
  38.     echo '  importvpncl.sh /dev/null'
  39.     echo
  40. }
  41.  
  42. # handle help/usage requests
  43. for opt; do case $opt in -h|--help) usage; exit 0;; esac; done
  44.  
  45. # process command line options/arguments
  46. while [ $# -gt 0 ]; do
  47.     case $1 in
  48.         '--nocommit') nocommit=;;
  49.                    *) if echo "$1" | grep -q '^-'; then
  50.                           echo "error: unknown option: $1"; exit 1
  51.                       else
  52.                           break 2
  53.                       fi;;
  54.     esac
  55.     shift
  56. done
  57. {
  58. # -------------------------- BEGIN GLOBAL CONSTANTS -------------------------- #
  59.  
  60. # openvpn client-specific nvram variables and default values
  61. #   generated by: nvram show 2>/dev/null | grep -E '^openvpncl_[^=]*=' | sort
  62. VAR_LIST='
  63. openvpncl_adv=0
  64. openvpncl_auth=none
  65. openvpncl_blockmulticast=0
  66. openvpncl_bridge=0
  67. openvpncl_ca=
  68. openvpncl_certtype=0
  69. openvpncl_cipher=
  70. openvpncl_client=
  71. openvpncl_config=
  72. openvpncl_dc1=CHACHA20-POLY1305
  73. openvpncl_dc2=AES-128-GCM
  74. openvpncl_dc3=AES-256-GCM
  75. openvpncl_enable=0
  76. openvpncl_fragment=
  77. openvpncl_fw=1
  78. openvpncl_ip=
  79. openvpncl_key=
  80. openvpncl_killswitch=0
  81. openvpncl_lzo=off
  82. openvpncl_mask=
  83. openvpncl_mit=1
  84. openvpncl_mssfix=0
  85. openvpncl_mtu=1400
  86. openvpncl_multirem=0
  87. openvpncl_nat=1
  88. openvpncl_pkcs12=
  89. openvpncl_proto=udp4
  90. openvpncl_randomsrv=0
  91. openvpncl_remoteip=0.0.0.0
  92. openvpncl_remoteport=1194
  93. openvpncl_route=
  94. openvpncl_scramble=off
  95. openvpncl_scrmblpw=o54a72ReutDK
  96. openvpncl_spbr=0
  97. openvpncl_splitdns=0
  98. openvpncl_tls_btn=3
  99. openvpncl_tlsauth=
  100. openvpncl_tlscip=0
  101. openvpncl_tuntap=tun
  102. openvpncl_upauth=0
  103. openvpncl_wdog=0
  104. openvpncl_wdog_pingip=8.8.8.8
  105. openvpncl_wdog_sleept=30
  106. '
  107. # dynamically generated nvram variables (deleted on reset)
  108. UNVAR_LIST='
  109. openvpncl_pass
  110. openvpncl_remoteip2
  111. openvpncl_remoteip3
  112. openvpncl_remoteip4
  113. openvpncl_remoteip5
  114. openvpncl_remoteport2
  115. openvpncl_remoteport3
  116. openvpncl_remoteport4
  117. openvpncl_remoteport5
  118. openvpncl_static
  119. openvpncl_user
  120. '
  121. PROTOCOL_LIST='udp udp4 udp6 tcp tcp4 tcp6 tcp-client tcp4-client tcp6-client'
  122.  
  123. CIPHER_LIST='
  124. CHACHA20-POLY1305
  125. AES-256-GCM
  126. AES-192-GCM
  127. AES-128-GCM
  128. AES-256-CBC
  129. AES-192-CBC
  130. AES-128-CBC
  131. '
  132. AUTH_LIST='sha512 sha256 sha1 md5 md4 none'
  133.  
  134. COMP_LZO_LIST='yes adaptive no'
  135.  
  136. COMPRESS_LIST='lz4 lz4-v2'
  137.  
  138. # handled directives (all others are ignored)
  139. HANDLED_DIR_LIST='
  140. <ca>
  141. <cert>
  142. <key>
  143. <pkcs12>
  144. <secret>
  145. <tls-auth>
  146. <tls-crypt>
  147. <tls-crypt-v2>
  148. <auth-user-pass>
  149. auth
  150. auth-user-pass
  151. cipher
  152. comp-lzo
  153. compress
  154. data-ciphers
  155. dev
  156. fragment
  157. key-direction
  158. mmsfix
  159. ncp-ciphers
  160. ns-cert-type
  161. pkcs12
  162. port
  163. proto
  164. remote
  165. remote-cert-tls
  166. tls-auth
  167. tls-crypt
  168. tls-crypt-v2
  169. verify-x509-name
  170. '
  171. # data cipher fields supported by gui
  172. DC_FIELDS='1 2 3'
  173.  
  174. # maximum number of remote directives supported by gui
  175. MAX_REMOTES=5
  176.  
  177. # temp file for additional config
  178. ADDN_CONFIG="/tmp/$(basename $0 .${0##*.}).$$.tmp"
  179.  
  180. # --------------------------- END GLOBAL CONSTANTS --------------------------- #
  181.  
  182. # -------------------------- BEGIN GLOBAL VARIABLES -------------------------- #
  183.  
  184. # track number of remote directives added to gui
  185. total_remotes=0
  186.  
  187. # default port (updated w/ port directive if present)
  188. default_port='1194'
  189.  
  190. # default protocol (updated w/ proto directive if present)
  191. default_proto='udp4'
  192.  
  193. # --------------------------- END GLOBAL VARIABLES --------------------------- #
  194.  
  195. # ----------------------------- BEGIN UTILITIES ------------------------------ #
  196.  
  197. # function to_lower( string [string ...] )
  198. to_lower() { echo "$@" | awk '{print tolower($0)}'; }
  199.  
  200. # function to_upper( string [string ...] )
  201. to_upper() { echo "$@" | awk '{print toupper($0)}'; }
  202.  
  203. # function get_field( num )
  204. get_field() { echo $line | awk "{print \$$1}"; }
  205.  
  206. # function get_textblock( directive )
  207. get_textblock() {
  208.     sed -ne "/<$1>/,/<\/$1/{/<$1>/!{/<\/$1>/!p;};}" "$CONFIG_FILE" | \
  209.     sed  -r '/^[[:space:]]*(#|;|$)/d'
  210. }
  211.  
  212. # function steer_protocol( protocol )
  213. steer_protocol() {
  214.     echo "$1" | \
  215.         # steer udp/tcp/tcp-client to udp4/tcp4/tcp4-client
  216.         sed -r 's/^(udp|tcp)$/\14/;s/^tcp-/tcp4-/' |
  217.  
  218.         # convert tcp/tcp4/tcp6 to tcp-client/tcp4-client/tcp6-client
  219.         sed -r 's/^(tcp(|4|6))$/\1-client/'
  220. }
  221.  
  222. # function write_addn_config( [string ...] )
  223. write_addn_config() {
  224.     { [ "$@" ] && echo "$@" || echo "$line"; } >> $ADDN_CONFIG
  225. }
  226.  
  227. # function reset_nvram()
  228. reset_nvram() {
  229.     local i
  230.  
  231.     # reset static nvram variables to their default values
  232.     for i in $VAR_LIST; do nvram set "$i"; done
  233.  
  234.     # remove dynamically generated nvram variables
  235.     for i in $UNVAR_LIST; do nvram unset "$i"; done
  236.  
  237.     # commit changes
  238.     [ ${nocommit+x} ] || nvram commit &>/dev/null
  239. }
  240.  
  241. # ------------------------------ END UTILITIES ------------------------------- #
  242.  
  243. # ------------------------------ BEGIN HANDLERS ------------------------------ #
  244.  
  245. # function handle_auth()
  246. handle_auth() {
  247.     local auth="$(to_lower $(get_field 2))"
  248.  
  249.     [ "$auth" ] || return
  250.  
  251.     # only update on exact match
  252.     if echo $AUTH_LIST | grep -q "\\b$auth\\b"; then
  253.         nvram set openvpncl_auth="$auth"
  254.     else
  255.         write_addn_config
  256.     fi
  257. }
  258.  
  259. # function handle_auth_user_pass()
  260. handle_auth_user_pass() {
  261.     if [ "$(get_field 2)" ]; then
  262.         write_addn_config
  263.     else
  264.         nvram set openvpncl_upauth='1'
  265.     fi
  266. }
  267.  
  268. # function handle_cipher()
  269. handle_cipher() {
  270.     local i cipher="$(to_upper $(get_field 2))"
  271.  
  272.     [ "$cipher" ] || return
  273.  
  274.     # check for disabled cipher
  275.     if [ "$cipher" == 'NONE' ]; then
  276.         nvram set openvpncl_cipher='none'
  277.         nvram set openvpncl_dc1='none'
  278.     # only update on exact match
  279.     elif echo $CIPHER_LIST | grep -q "\\b$cipher\\b"; then
  280.         nvram set openvpncl_cipher="$cipher"
  281.         nvram set openvpncl_dc1="$cipher"
  282.     else
  283.         write_addn_config
  284.     fi
  285. }
  286.  
  287. # function handle_comp_lzo()
  288. handle_comp_lzo() {
  289.     local comp_lzo="$(to_lower $(get_field 2))"
  290.  
  291.     # unspecified type means default (adaptive)
  292.     if [ ! "$comp_lzo" ]; then
  293.         nvram set openvpncl_lzo='adaptive'
  294.     # else only update on exact match
  295.     elif echo $COMP_LZO_LIST | grep -q "\\b$comp_lzo\\b"; then
  296.         nvram set openvpncl_lzo="$comp_lzo"
  297.     else
  298.         write_addn_config
  299.     fi
  300. }
  301.  
  302. # function handle_compress()
  303. handle_compress() {
  304.     local compress="$(to_lower $(get_field 2))"
  305.  
  306.     # unspecified type means compression is off, but packet framing is
  307.     # still enabled allowing a different setting to be pushed later
  308.     if [ ! "$compress" ]; then
  309.         nvram set openvpncl_lzo='compress'
  310.     # else only update on exact match
  311.     elif echo $COMPRESS_LIST | grep -q "\\b$compress\\b"; then
  312.         nvram set openvpncl_lzo="compress $compress"
  313.     else
  314.         write_addn_config
  315.     fi
  316. }
  317.  
  318. # function handle_data_ciphers()
  319. handle_data_ciphers() {
  320.     local i cipher cipher_found
  321.     local ciphers="$(to_upper $(get_field 2 | tr ':' ' '))"
  322.  
  323.     [ "$ciphers" ] || return
  324.  
  325.     # check for disabled data ciphers
  326.     [ "$ciphers" == 'NONE' ] && { nvram set openvpncl_dc1='none'; return; }
  327.  
  328.     # update individual data cipher fields
  329.     for i in $DC_FIELDS; do
  330.         for cipher in $ciphers; do
  331.             # only update on exact match
  332.             if echo $CIPHER_LIST | grep -q "\\b$cipher\\b"; then
  333.                 nvram set openvpncl_dc${i}="$cipher"
  334.  
  335.                 # eliminate this cipher from further consideration
  336.                 ciphers="$(echo $ciphers | sed s/\\b$cipher\\b//g)"
  337.  
  338.                 cipher_found=
  339.                 continue 2
  340.             fi
  341.         done
  342.         # if we never found a match, there's no point continuing
  343.         break
  344.     done
  345.  
  346.     [ ${cipher_found+x} ] || write_addn_config
  347. }
  348.  
  349. # function handle_dev()
  350. handle_dev() {
  351.     local dev="$(to_lower $(get_field 2))"
  352.  
  353.     if   [ "${dev:0:3}" == 'tun' ]; then
  354.         nvram set openvpncl_tuntap='tun'
  355.     elif [ "${dev:0:3}" == 'tap' ]; then
  356.         nvram set openvpncl_tuntap='tap'
  357.  
  358.         # bridge tunnel (tap) to private network (br0)
  359.         nvram set openvpncl_bridge='1'
  360.  
  361.         # disable nat
  362.         nvram set openvpncl_nat='0'
  363.     fi
  364. }
  365.  
  366. # function handle_fragment()
  367. handle_fragment() { nvram set openvpncl_fragment="$(get_field 2)"; }
  368.  
  369. # function handle_key_direction()
  370. handle_key_direction() {
  371.     local key_direction="$(get_field 2)"
  372.  
  373.     [ "$key_direction" ] || return
  374.  
  375.     # key direction default is 1; only need directive if something else
  376.     [ "$key_direction" != '1' ] && write_addn_config
  377. }
  378.  
  379. # function handle_mssfix()
  380. handle_mssfix() { nvram set openvpncl_mssfix='1'; }
  381.  
  382. # function handle_ncp_ciphers()
  383. handle_ncp_ciphers() { [ "$(get_field 2)" ] && write_addn_config; }
  384.  
  385. # function handle_ns_cert_type()
  386. handle_ns_cert_type() { handle_remote_cert_tls; }
  387.  
  388. # function handle_pkcs12()
  389. handle_pkcs12() { [ "$(get_field 2)" ] && write_addn_config; }
  390.  
  391. # function handle_port()
  392. handle_port() { [ "$(get_field 2)" ] && default_port="$(get_field 2)"; }
  393.  
  394. # function handle_proto()
  395. handle_proto() {
  396.     local proto="$(to_lower $(get_field 2))"
  397.  
  398.     [ "$proto" ] || return
  399.  
  400.     # only update on exact match
  401.     if echo $PROTOCOL_LIST | grep -q "\\b$proto\\b"; then
  402.         default_proto="$(steer_protocol $proto)"
  403.     else
  404.         write_addn_config
  405.     fi
  406. }
  407.  
  408. # function handle_remote()
  409. handle_remote() {
  410.     local ip="$(get_field 2)"
  411.     local port="$(get_field 3)"
  412.     local proto="$(to_lower $(get_field 4))"
  413.  
  414.     [ "$ip"    ] || return
  415.     [ "$port"  ] || port="$default_port"
  416.     [ "$proto" ] || proto="$default_proto"
  417.  
  418.     proto="$(steer_protocol $proto)"
  419.  
  420.     if [ $((total_remotes)) -lt $MAX_REMOTES ]; then
  421.         if [ $total_remotes -eq 0 ]; then
  422.             let $total_remotes++
  423.             nvram set openvpncl_remoteip="$ip"
  424.             nvram set openvpncl_remoteport="$port"
  425.             nvram set openvpncl_proto="$proto"
  426.         elif [ "$proto" == "$(nvram get openvpncl_proto)" ]; then
  427.             let total_remotes++
  428.             nvram set openvpncl_remoteip${total_remotes}="$ip"
  429.             nvram set openvpncl_remoteport${total_remotes}="$port"
  430.             nvram set openvpncl_multirem='1'
  431.             nvram set openvpncl_randomsrv='1'
  432.         fi
  433.     elif [ "$proto" == "$(nvram get openvpncl_proto)" ]; then
  434.         write_addn_config \
  435.             "$(echo remote $ip $port $proto | sed 's/[[:space:]]*$//g')"
  436.     fi
  437. }
  438.  
  439. # function handle_remote_cert_tls()
  440. handle_remote_cert_tls() {
  441.     if [ "$(to_lower $(get_field 2))" == 'server' ]; then
  442.         nvram set openvpncl_certtype='1'
  443.     fi
  444. }
  445.  
  446. # function handle_tls_auth()
  447. handle_tls_auth() { [ "$(get_field 2)" ] && write_addn_config; }
  448.  
  449. # function handle_tls_crypt()
  450. handle_tls_crypt() { [ "$(get_field 2)" ] && write_addn_config; }
  451.  
  452. # function handle_tls_crypt_v2()
  453. handle_tls_crypt_v2() { [ "$(get_field 2)" ] && write_addn_config; }
  454.  
  455. # function handle_verify_x509_name()
  456. handle_verify_x509_name() { [ "$(get_field 2)" ] && write_addn_config; }
  457.  
  458. # ------------------------------- END HANDLERS ------------------------------- #
  459.  
  460. # ----------------------- BEGIN PROCESSING CONFIG FILE ----------------------- #
  461.  
  462. # if no user-provided config file, assume default
  463. [ "$1" ] && CONFIG_FILE="$1" || CONFIG_FILE='/tmp/vpnupload.conf'
  464.  
  465. if [[ "$CONFIG_FILE" != '/dev/null' && ! -f "$CONFIG_FILE" ]]; then
  466.     echo "error: file not found: $CONFIG_FILE"
  467.     exit 1
  468. fi
  469.  
  470. # reset nvram variables to defaults
  471. reset_nvram
  472.  
  473. # no need to go any further if config file is empty
  474. [ -s "$CONFIG_FILE" ] || exit 0
  475.  
  476. # convert config file from dos to linux file format (as necessary)
  477. grep -q '\r' "$CONFIG_FILE" && sed -i 's/\r//g' "$CONFIG_FILE"
  478.  
  479. # enable openvpn client
  480. nvram set openvpncl_enable='1'
  481.  
  482. # reconfigure openvpn client defaults to comply w/ openvpn defaults
  483. nvram set openvpncl_auth=
  484. for i in $DC_FIELDS; do nvram set openvpncl_dc${i}=; done
  485.  
  486. # identify handled directives from config file
  487. lines="$(sed -rn \
  488.    "s/^(|--)(($(echo $HANDLED_DIR_LIST | tr ' ' '|'))([[:space:]].*|$))/\2/p" \
  489.        "$CONFIG_FILE")"
  490.  
  491. OIFS="$IFS"; IFS=$'\n'
  492. for line in $lines; do
  493.     IFS="$OIFS"
  494.  
  495.     # isolate directive from arguments (if any)
  496.     dir="${line%%[[:space:]]*}"
  497.  
  498.     # these directive *must* be processed first!
  499.     case $dir in 'cipher'|'port'|'proto') handle_${dir//-/_};; esac
  500.  
  501.     IFS=$'\n'
  502. done
  503.  
  504. for line in $lines; do
  505.     IFS="$OIFS"
  506.  
  507.     # isolate directive from arguments (if any)
  508.     dir="${line%%[[:space:]]*}"
  509.  
  510.     case $dir in
  511.       # ignore previously processed directives
  512.         'cipher'|'port'|'proto') ;;
  513.  
  514.       # handle multi-line directives
  515.                '<ca>') nvram set openvpncl_ca="$(get_textblock ca)";;
  516.              '<cert>') nvram set openvpncl_client="$(get_textblock cert)";;
  517.               '<key>') nvram set openvpncl_key="$(get_textblock key)";;
  518.            '<pkcs12>') nvram set openvpncl_pkcs12="$(get_textblock pkcs12)";;
  519.            '<secret>') nvram set openvpncl_static="$(get_textblock secret)"
  520.                        nvram set openvpncl_tls_btn='2';;
  521.          '<tls-auth>') nvram set openvpncl_tlsauth="$(get_textblock tls-auth)"
  522.                        nvram set openvpncl_tls_btn='0';;
  523.         '<tls-crypt>') nvram set openvpncl_tlsauth="$(get_textblock tls-crypt)"
  524.                        nvram set openvpncl_tls_btn='1';;
  525.      '<tls-crypt-v2>') nvram set openvpncl_tlsauth="$(get_textblock tls-crypt-v2)"
  526.                        nvram set openvpncl_tls_btn='4';;
  527.    '<auth-user-pass>') up="$(get_textblock auth-user-pass)"
  528.                        nvram set openvpncl_user=$(echo -e "$up" | awk 'NR==1{print $1}')
  529.                        nvram set openvpncl_pass=$(echo -e "$up" | awk 'NR==2{print $1}')
  530.                        nvram set openvpncl_upauth='1';;
  531.  
  532.       # handle single-line directives
  533.                     *) handle_${dir//-/_};;
  534.     esac
  535.  
  536.     IFS=$'\n'
  537. done
  538. IFS="$OIFS"
  539.  
  540. # ignore ipv6 pushed routes when using ipv4 protocols
  541. if echo "$(nvram get openvpncl_proto)" | grep -Eq '^(udp|tcp)4'; then
  542.     write_addn_config 'pull-filter ignore ifconfig-ipv6'
  543.     write_addn_config 'pull-filter ignore route-ipv6'
  544.     write_addn_config 'block-ipv6'
  545. fi
  546.  
  547. # save additional config (if any)
  548. [ -s $ADDN_CONFIG ] && nvram set openvpncl_config="$(cat $ADDN_CONFIG)"
  549.  
  550. # commit changes
  551. [ ${nocommit+x} ] || nvram commit &>/dev/null
  552.  
  553. # cleanup
  554. rm -f $ADDN_CONFIG
  555.  
  556. # ------------------------ END PROCESSING CONFIG FILE ------------------------ #
  557.  
  558. # debug: dump config file and updated nvram variables for review
  559. if [ ${DEBUG+x} ]; then
  560.     set +x
  561.     echo '<input>'
  562.     cat "$CONFIG_FILE"
  563.     echo '</input>'
  564.     echo '<output>'
  565.     nvram show 2>/dev/null | grep -E '^openvpncl_[^=]*=' | sort
  566.     echo '</output>'
  567.     set -x
  568. fi
  569.  
  570. exit 0
  571. } &>$LOG
Add Comment
Please, Sign In to add comment