zyxel_gs1900.sh 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. #!/usr/bin/env sh
  2. # Deploy certificates to Zyxel GS1900 series switches
  3. #
  4. # This script uses the https web administration interface in order
  5. # to upload updated certificates to Zyxel GS1900 series switches.
  6. # Only a few models have been tested but untested switches from the
  7. # same model line may work as well. If you test and confirm a switch
  8. # as working please submit a pull request updating this compatibility
  9. # list!
  10. #
  11. # Known Issues:
  12. # 1. This is a consumer grade switch and is a bit underpowered
  13. # the longer the RSA key size the slower your switch web UI
  14. # will be. RSA 2048 will work, RSA 4096 will work but you may
  15. # experience performance problems.
  16. # 2. You must use RSA certificates. The switch will reject EC-256
  17. # and EC-384 certificates in firmware 2.80
  18. # See: https://community.zyxel.com/en/discussion/21506/bug-cannot-import-ssl-cert-on-gs1900-8-and-gs1900-24e-firmware-v2-80/
  19. #
  20. # Current GS1900 Switch Compatibility:
  21. # GS1900-8 - Working as of firmware V2.80
  22. # GS1900-8HP - Untested
  23. # GS1900-10HP - Untested
  24. # GS1900-16 - Untested
  25. # GS1900-24 - Untested
  26. # GS1900-24E - Working as of firmware V2.80
  27. # GS1900-24EP - Untested
  28. # GS1900-24HP - Untested
  29. # GS1900-48 - Untested
  30. # GS1900-48HP - Untested
  31. #
  32. # Prerequisite Setup Steps:
  33. # 1. Install at least firmware V2.80 on your switch
  34. # 2. Enable HTTPS web management on your switch
  35. #
  36. # Usage:
  37. # 1. Ensure the switch has firmware V2.80 or later.
  38. # 2. Ensure the switch has HTTPS management enabled.
  39. # 3. Set the appropriate environment variables for your environment.
  40. #
  41. # DEPLOY_ZYXEL_SWITCH - The switch hostname. (Default: _cdomain)
  42. # DEPLOY_ZYXEL_SWITCH_USER - The webadmin user. (Default: admin)
  43. # DEPLOY_ZYXEL_SWITCH_PASSWORD - The webadmin password for the switch.
  44. # DEPLOY_ZYXEL_SWITCH_REBOOT - If "1" reboot after update. (Default: "0")
  45. #
  46. # 4. Run the deployment plugin:
  47. # acme.sh --deploy --deploy-hook zyxel_gs1900 -d example.com
  48. #
  49. # returns 0 means success, otherwise error.
  50. #domain keyfile certfile cafile fullchain
  51. zyxel_gs1900_deploy() {
  52. _zyxel_gs1900_minimum_firmware_version="v2.80"
  53. _cdomain="$1"
  54. _ckey="$2"
  55. _ccert="$3"
  56. _cca="$4"
  57. _cfullchain="$5"
  58. _debug _cdomain "$_cdomain"
  59. _debug2 _ckey "$_ckey"
  60. _debug _ccert "$_ccert"
  61. _debug _cca "$_cca"
  62. _debug _cfullchain "$_cfullchain"
  63. _getdeployconf DEPLOY_ZYXEL_SWITCH
  64. _getdeployconf DEPLOY_ZYXEL_SWITCH_USER
  65. _getdeployconf DEPLOY_ZYXEL_SWITCH_PASSWORD
  66. _getdeployconf DEPLOY_ZYXEL_SWITCH_REBOOT
  67. if [ -z "$DEPLOY_ZYXEL_SWITCH" ]; then
  68. DEPLOY_ZYXEL_SWITCH="$_cdomain"
  69. fi
  70. if [ -z "$DEPLOY_ZYXEL_SWITCH_USER" ]; then
  71. DEPLOY_ZYXEL_SWITCH_USER="admin"
  72. fi
  73. if [ -z "$DEPLOY_ZYXEL_SWITCH_PASSWORD" ]; then
  74. DEPLOY_ZYXEL_SWITCH_PASSWORD="1234"
  75. fi
  76. if [ -z "$DEPLOY_ZYXEL_SWITCH_REBOOT" ]; then
  77. DEPLOY_ZYXEL_SWITCH_REBOOT="0"
  78. fi
  79. _savedeployconf DEPLOY_ZYXEL_SWITCH "$DEPLOY_ZYXEL_SWITCH"
  80. _savedeployconf DEPLOY_ZYXEL_SWITCH_USER "$DEPLOY_ZYXEL_SWITCH_USER"
  81. _savedeployconf DEPLOY_ZYXEL_SWITCH_PASSWORD "$DEPLOY_ZYXEL_SWITCH_PASSWORD"
  82. _savedeployconf DEPLOY_ZYXEL_SWITCH_REBOOT "$DEPLOY_ZYXEL_SWITCH_REBOOT"
  83. _debug DEPLOY_ZYXEL_SWITCH "$DEPLOY_ZYXEL_SWITCH"
  84. _debug DEPLOY_ZYXEL_SWITCH_USER "$DEPLOY_ZYXEL_SWITCH_USER"
  85. _secure_debug DEPLOY_ZYXEL_SWITCH_PASSWORD "$DEPLOY_ZYXEL_SWITCH_PASSWORD"
  86. _debug DEPLOY_ZYXEL_SWITCH_REBOOT "$DEPLOY_ZYXEL_SWITCH_REBOOT"
  87. _zyxel_switch_base_uri="https://${DEPLOY_ZYXEL_SWITCH}"
  88. _info "Beginning to deploy to a Zyxel GS1900 series switch at ${_zyxel_switch_base_uri}."
  89. _zyxel_gs1900_deployment_precheck || return $?
  90. _zyxel_gs1900_should_update
  91. if [ "$?" != "0" ]; then
  92. _info "The switch already has our certificate installed. No update required."
  93. return 0
  94. else
  95. _info "The switch does not yet have our certificate installed."
  96. fi
  97. _info "Logging into the switch web interface."
  98. _zyxel_gs1900_login || return $?
  99. _info "Validating the switch is compatible with this deployment process."
  100. _zyxel_gs1900_validate_device_compatibility || return $?
  101. _info "Uploading the certificate."
  102. _zyxel_gs1900_upload_certificate || return $?
  103. if [ "$DEPLOY_ZYXEL_SWITCH_REBOOT" = "1" ]; then
  104. _info "Rebooting the switch."
  105. _zyxel_gs1900_trigger_reboot || return $?
  106. fi
  107. return 0
  108. }
  109. _zyxel_gs1900_deployment_precheck() {
  110. # Initialize the keylength if it isn't already
  111. if [ -z "$Le_Keylength" ]; then
  112. Le_Keylength=""
  113. fi
  114. if _isEccKey "$Le_Keylength"; then
  115. _info "Warning: Zyxel GS1900 switches are not currently known to work with ECC keys!"
  116. _info "You can continue, but your switch may reject your key."
  117. elif [ -n "$Le_Keylength" ] && [ "$Le_Keylength" -gt "2048" ]; then
  118. _info "Warning: Your RSA key length is greater than 2048!"
  119. _info "You can continue, but you may experience performance issues in the web administration interface."
  120. fi
  121. # Check the server for some common failure modes prior to authentication and certificate upload in order to avoid
  122. # sending a certificate when we may not want to.
  123. test_login_response=$(_post "username=test&password=test&login=true;" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" 2>&1)
  124. test_login_page_exitcode="$?"
  125. _debug3 "Test Login Response: ${test_login_response}"
  126. if [ "$test_login_page_exitcode" -ne "0" ]; then
  127. if { [ "${ACME_USE_WGET:-0}" = "0" ] && [ "$test_login_page_exitcode" = "60" ]; } || { [ "${ACME_USE_WGET:-0}" = "1" ] && [ "$test_login_page_exitcode" = "5" ]; }; then
  128. _err "The SSL certificate at $_zyxel_switch_base_uri could not be validated."
  129. _err "Please double check your hostname, port, and that you are actually connecting to your switch."
  130. _err "If the problem persists then please ensure that the certificate is not self-signed, has not"
  131. _err "expired, and matches the switch hostname. If you expect validation to fail then you can disable"
  132. _err "certificate validation by running with --insecure."
  133. return 1
  134. elif [ "${ACME_USE_WGET:-0}" = "0" ] && [ "$test_login_page_exitcode" = "56" ]; then
  135. _debug3 "Intentionally ignore curl exit code 56 in our precheck"
  136. else
  137. _err "Failed to submit the initial login attempt to $_zyxel_switch_base_uri."
  138. return 1
  139. fi
  140. fi
  141. }
  142. _zyxel_gs1900_login() {
  143. # Login to the switch and set the appropriate auth cookie in _H1
  144. username_encoded=$(printf "%s" "$DEPLOY_ZYXEL_SWITCH_USER" | _url_encode)
  145. password_encoded=$(_zyxel_gs1900_password_obfuscate "$DEPLOY_ZYXEL_SWITCH_PASSWORD" | _url_encode)
  146. login_response=$(_post "username=${username_encoded}&password=${password_encoded}&login=true;" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" | tr -d '\n')
  147. auth_response=$(_post "authId=${login_response}&login_chk=true" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=0.html" '' "POST" "application/x-www-form-urlencoded" | tr -d '\n')
  148. if [ "$auth_response" != "OK" ]; then
  149. _err "Login failed due to invalid credentials."
  150. _err "Please double check the configured username and password and try again."
  151. return 1
  152. fi
  153. sessionid=$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'HTTPS_XSSID=[^;]*;' | tr -d ';')
  154. _secure_debug2 "sessionid" "$sessionid"
  155. export _H1="Cookie: $sessionid"
  156. _secure_debug2 "_H1" "$_H1"
  157. return 0
  158. }
  159. _zyxel_gs1900_validate_device_compatibility() {
  160. # Check the switches model and firmware version and throw errors
  161. # if this script isn't compatible.
  162. device_info_html=$(_get "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=12" | tr -d '\n')
  163. model_name=$(_zyxel_gs1900_get_model "$device_info_html")
  164. _debug2 "model_name" "$model_name"
  165. if [ -z "$model_name" ]; then
  166. _err "Could not find the switch model name."
  167. _err "Please re-run with --debug and report a bug."
  168. return $?
  169. fi
  170. if ! expr "$model_name" : "GS1900-" >/dev/null; then
  171. _err "Switch is an unsupported model: $model_name"
  172. return 1
  173. fi
  174. firmware_version=$(_zyxel_gs1900_get_firmware_version "$device_info_html")
  175. _debug2 "firmware_version" "$firmware_version"
  176. if [ -z "$firmware_version" ]; then
  177. _err "Could not find the switch firmware version."
  178. _err "Please re-run with --debug and report a bug."
  179. return $?
  180. fi
  181. _debug2 "_zyxel_gs1900_minimum_firmware_version" "$_zyxel_gs1900_minimum_firmware_version"
  182. minimum_major_version=$(_zyxel_gs1900_parse_major_version "$_zyxel_gs1900_minimum_firmware_version")
  183. _debug2 "minimum_major_version" "$minimum_major_version"
  184. minimum_minor_version=$(_zyxel_gs1900_parse_minor_version "$_zyxel_gs1900_minimum_firmware_version")
  185. _debug2 "minimum_minor_version" "$minimum_minor_version"
  186. _debug2 "firmware_version" "$firmware_version"
  187. firmware_major_version=$(_zyxel_gs1900_parse_major_version "$firmware_version")
  188. _debug2 "firmware_major_version" "$firmware_major_version"
  189. firmware_minor_version=$(_zyxel_gs1900_parse_minor_version "$firmware_version")
  190. _debug2 "firmware_minor_version" "$firmware_minor_version"
  191. _ret=0
  192. if [ "$firmware_major_version" -lt "$minimum_major_version" ]; then
  193. _ret=1
  194. elif [ "$firmware_major_version" -eq "$minimum_major_version" ] && [ "$firmware_minor_version" -lt "$minimum_minor_version" ]; then
  195. _ret=1
  196. fi
  197. if [ "$_ret" != "0" ]; then
  198. _err "Unsupported firmware version $firmware_version. Please upgrade to at least version $_zyxel_gs1900_minimum_firmware_version."
  199. fi
  200. return $?
  201. }
  202. _zyxel_gs1900_should_update() {
  203. # Get the remote certificate serial number
  204. _remote_cert=$(${ACME_OPENSSL_BIN:-openssl} s_client -showcerts -connect "${DEPLOY_ZYXEL_SWITCH}:443" 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')
  205. _debug3 "_remote_cert" "$_remote_cert"
  206. _remote_cert_serial=$(printf "%s" "${_remote_cert}" | ${ACME_OPENSSL_BIN:-openssl} x509 -noout -serial)
  207. _debug2 "_remote_cert_serial" "$_remote_cert_serial"
  208. # Get our certificate serial number
  209. _our_cert_serial=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -serial <"${_ccert}")
  210. _debug2 "_our_cert_serial" "$_our_cert_serial"
  211. [ "${_remote_cert_serial}" != "${_our_cert_serial}" ]
  212. }
  213. _zyxel_gs1900_upload_certificate() {
  214. # Generate a PKCS12 certificate with a temporary password since the web interface
  215. # requires a password be present. Then upload that certificate.
  216. temp_cert_password=$(head /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 64)
  217. _secure_debug2 "temp_cert_password" "$temp_cert_password"
  218. temp_pkcs12="$(_mktemp)"
  219. _debug2 "temp_pkcs12" "$temp_pkcs12"
  220. _toPkcs "$temp_pkcs12" "$_ckey" "$_ccert" "$_cca" "$temp_cert_password"
  221. if [ "$?" != "0" ]; then
  222. _err "Failed to generate a pkcs12 certificate."
  223. _err "Please re-run with --debug and report a bug."
  224. # ensure the temporary certificate file is cleaned up
  225. [ -f "${temp_pkcs12}" ] && rm -f "${temp_pkcs12}"
  226. return $?
  227. fi
  228. # Load the upload page
  229. upload_page_html=$(_get "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=5914" | tr -d '\n')
  230. # Get the first instance of XSSID from the upload page
  231. form_xss_value=$(printf "%s" "$upload_page_html" | _egrep_o 'name="XSSID"\s*value="[^"]+"' | sed 's/^.*="\([^"]\{1,\}\)"$/\1/g' | head -n 1)
  232. _secure_debug2 "form_xss_value" "$form_xss_value"
  233. _info "Generating the certificate upload request"
  234. upload_post_request="$(_mktemp)"
  235. upload_post_boundary="---------------------------$(date +%Y%m%d%H%M%S)"
  236. {
  237. printf -- "--%s\r\n" "${upload_post_boundary}"
  238. printf "Content-Disposition: form-data; name=\"XSSID\"\r\n\r\n%s\r\n" "${form_xss_value}"
  239. printf -- "--%s\r\n" "${upload_post_boundary}"
  240. printf "Content-Disposition: form-data; name=\"http_file\"; filename=\"temp_pkcs12.pfx\"\r\n"
  241. printf "Content-Type: application/pkcs12\r\n\r\n"
  242. cat "${temp_pkcs12}"
  243. printf "\r\n"
  244. printf -- "--%s\r\n" "${upload_post_boundary}"
  245. printf "Content-Disposition: form-data; name=\"pwd\"\r\n\r\n%s\r\n" "${temp_cert_password}"
  246. printf -- "--%s\r\n" "${upload_post_boundary}"
  247. printf "Content-Disposition: form-data; name=\"cmd\"\r\n\r\n%s\r\n" "31"
  248. printf -- "--%s\r\n" "${upload_post_boundary}"
  249. printf "Content-Disposition: form-data; name=\"sysSubmit\"\r\n\r\n%s\r\n" "Import"
  250. printf -- "--%s--\r\n" "${upload_post_boundary}"
  251. } >"${upload_post_request}"
  252. _info "Upload certificate to the switch"
  253. # Unfortunately we cannot rely upon the switch response across switch models
  254. # to return a consistent body return - so we cannot inspect the result of this
  255. # upload to determine success.
  256. upload_response=$(_zyxel_upload_pkcs12 "${upload_post_request}" "${upload_post_boundary}" 2>&1)
  257. _debug3 "Upload response: ${upload_response}"
  258. rm "${upload_post_request}"
  259. # Pause for a few seconds to give the switch a chance to process the certificate
  260. # For some reason I've found this to be necessary on my GS1900-24E
  261. _debug2 "Waiting 4 seconds for the switch to process the newly uploaded certificate."
  262. sleep "4"
  263. # Check to see whether or not our update was successful
  264. _ret=0
  265. _zyxel_gs1900_should_update
  266. if [ "$?" != "0" ]; then
  267. _info "The certificate was updated successfully"
  268. else
  269. _ret=1
  270. _err "The certificate upload does not appear to have worked."
  271. _err "The remote certificate does not match the certificate we tried to upload."
  272. _err "Please re-run with --debug 2 and review for unexpected errors. If none can be found please submit a bug."
  273. fi
  274. # ensure the temporary files are cleaned up
  275. [ -f "${temp_pkcs12}" ] && rm -f "${temp_pkcs12}"
  276. return $_ret
  277. }
  278. # make the certificate upload request using either
  279. # --data binary with @ for file access in CURL
  280. # or using --post-file for wget to ensure we upload
  281. # the pkcs12 without getting tripped up on null bytes
  282. #
  283. # Usage _zyxel_upload_pkcs12 [body file name] [post boundary marker]
  284. _zyxel_upload_pkcs12() {
  285. bodyfilename="$1"
  286. multipartformmarker="$2"
  287. _post_url="${_zyxel_switch_base_uri}/cgi-bin/httpuploadcert.cgi"
  288. httpmethod="POST"
  289. _postContentType="multipart/form-data; boundary=${multipartformmarker}"
  290. if [ -z "$httpmethod" ]; then
  291. httpmethod="POST"
  292. fi
  293. _debug $httpmethod
  294. _debug "_post_url" "$_post_url"
  295. _debug2 "bodyfilename" "$bodyfilename"
  296. _debug2 "_postContentType" "$_postContentType"
  297. _inithttp
  298. if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
  299. _CURL="$_ACME_CURL"
  300. if [ "$HTTPS_INSECURE" ]; then
  301. _CURL="$_CURL --insecure "
  302. fi
  303. if [ "$httpmethod" = "HEAD" ]; then
  304. _CURL="$_CURL -I "
  305. fi
  306. _debug "_CURL" "$_CURL"
  307. response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data-binary "@${bodyfilename}" "$_post_url")"
  308. _ret="$?"
  309. if [ "$_ret" != "0" ]; then
  310. _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
  311. if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
  312. _err "Here is the curl dump log:"
  313. _err "$(cat "$_CURL_DUMP")"
  314. fi
  315. fi
  316. elif [ "$_ACME_WGET" ]; then
  317. _WGET="$_ACME_WGET"
  318. if [ "$HTTPS_INSECURE" ]; then
  319. _WGET="$_WGET --no-check-certificate "
  320. fi
  321. _debug "_WGET" "$_WGET"
  322. response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-file="${bodyfilename}" "$_post_url" 2>"$HTTP_HEADER")"
  323. _ret="$?"
  324. if [ "$_ret" = "8" ]; then
  325. _ret=0
  326. _debug "wget returned 8 as the server returned a 'Bad Request' response. Let's process the response later."
  327. fi
  328. if [ "$_ret" != "0" ]; then
  329. _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
  330. fi
  331. if _contains "$_WGET" " -d "; then
  332. # Demultiplex wget debug output
  333. cat "$HTTP_HEADER" >&2
  334. _sed_i '/^[^ ][^ ]/d; /^ *$/d' "$HTTP_HEADER"
  335. fi
  336. # remove leading whitespaces from header to match curl format
  337. _sed_i 's/^ //g' "$HTTP_HEADER"
  338. else
  339. _ret="$?"
  340. _err "Neither curl nor wget have been found, cannot make $httpmethod request."
  341. fi
  342. _debug "_ret" "$_ret"
  343. printf "%s" "$response"
  344. return $_ret
  345. }
  346. _zyxel_gs1900_trigger_reboot() {
  347. # Trigger a reboot via the management reboot page in the web ui
  348. reboot_page_html=$(_get "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi?cmd=5888" | tr -d '\n')
  349. reboot_xss_value=$(printf "%s" "$reboot_page_html" | _egrep_o 'name="XSSID"\s*value="[^"]+"' | sed 's/^.*="\([^"]\{1,\}\)"$/\1/g')
  350. _secure_debug2 "reboot_xss_value" "$reboot_xss_value"
  351. reboot_response_html=$(_post "XSSID=${reboot_xss_value}&cmd=5889&sysSubmit=Reboot" "${_zyxel_switch_base_uri}/cgi-bin/dispatcher.cgi" '' "POST" "application/x-www-form-urlencoded")
  352. reboot_message=$(printf "%s" "$reboot_response_html" | tr -d '\t\r\n\v\f' | _egrep_o "Rebooting now...")
  353. if [ -z "$reboot_message" ]; then
  354. _err "Failed to trigger switch reboot!"
  355. return 1
  356. fi
  357. return 0
  358. }
  359. # password
  360. _zyxel_gs1900_password_obfuscate() {
  361. # Return the password obfuscated via the same method used by the
  362. # switch's web UI login process
  363. echo "$1" | awk '{
  364. encoded = "";
  365. password = $1;
  366. allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  367. len = length($1);
  368. pwi = length($1);
  369. for (i=1; i <= (321 - pwi); i++)
  370. {
  371. if (0 == i % 5 && pwi > 0)
  372. {
  373. encoded = (encoded)(substr(password, pwi--, 1));
  374. }
  375. else if (i == 123)
  376. {
  377. if (len < 10)
  378. {
  379. encoded = (encoded)(0);
  380. }
  381. else
  382. {
  383. encoded = (encoded)(int(len / 10));
  384. }
  385. }
  386. else if (i == 289)
  387. {
  388. encoded = (encoded)(len % 10)
  389. }
  390. else
  391. {
  392. encoded = (encoded)(substr(allowed, int(rand() * length(allowed)), 1))
  393. }
  394. }
  395. printf("%s", encoded);
  396. }'
  397. }
  398. # html label
  399. _zyxel_html_table_lookup() {
  400. # Look up a value in the html representing the status page of the switch
  401. # when provided with the html of the page and the label (i.e. "Model Name:")
  402. html="$1"
  403. label=$(printf "%s" "$2" | tr -d ' ')
  404. lookup_result=$(printf "%s" "$html" | tr -d "\t\r\n\v\f" | sed 's/<tr>/\n<tr>/g' | sed 's/<td[^>]*>/<td>/g' | tr -d ' ' | grep -i "$label" | sed "s/<tr><td>$label<\/td><td>\([^<]\{1,\}\)<\/td><\/tr>/\1/i")
  405. printf "%s" "$lookup_result"
  406. return 0
  407. }
  408. # html
  409. _zyxel_gs1900_get_model() {
  410. html="$1"
  411. model_name=$(_zyxel_html_table_lookup "$html" "Model Name:")
  412. printf "%s" "$model_name"
  413. }
  414. # html
  415. _zyxel_gs1900_get_firmware_version() {
  416. html="$1"
  417. firmware_version=$(_zyxel_html_table_lookup "$html" "Firmware Version:" | _egrep_o "V[^.]+.[^(]+")
  418. printf "%s" "$firmware_version"
  419. }
  420. # version_number
  421. _zyxel_gs1900_parse_major_version() {
  422. printf "%s" "$1" | sed 's/^V\([0-9]\{1,\}\).\{1,\}$/\1/gi'
  423. }
  424. # version_number
  425. _zyxel_gs1900_parse_minor_version() {
  426. printf "%s" "$1" | sed 's/^.\{1,\}\.\([0-9]\{1,\}\)$/\1/gi'
  427. }