You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
7.1 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. #!/usr/bin/env sh
  2. #OPNsense Bind API
  3. #https://docs.opnsense.org/development/api.html
  4. #
  5. #OPNs_Host="opnsense.example.com"
  6. #OPNs_Port="443"
  7. # optional, defaults to 443 if unset
  8. #OPNs_Key="qocfU9RSbt8vTIBcnW8bPqCrpfAHMDvj5OzadE7Str+rbjyCyk7u6yMrSCHtBXabgDDXx/dY0POUp7ZA"
  9. #OPNs_Token="pZEQ+3ce8dDlfBBdg3N8EpqpF5I1MhFqdxX06le6Gl8YzyQvYCfCzNaFX9O9+IOSyAs7X71fwdRiZ+Lv"
  10. #OPNs_Api_Insecure=0
  11. # optional, defaults to 0 if unset
  12. # Set 1 for insecure and 0 for secure -> difference is whether ssl cert is checked for validity (0) or whether it is just accepted (1)
  13. ######## Public functions #####################
  14. #Usage: add _acme-challenge.www.domain.com "123456789ABCDEF0000000000000000000000000000000000000"
  15. #fulldomain
  16. #txtvalue
  17. OPNs_DefaultPort=443
  18. OPNs_DefaultApi_Insecure=0
  19. dns_opnsense_add() {
  20. fulldomain=$1
  21. txtvalue=$2
  22. _opns_check_auth || return 1
  23. if ! set_record "$fulldomain" "$txtvalue"; then
  24. return 1
  25. fi
  26. return 0
  27. }
  28. #fulldomain
  29. dns_opnsense_rm() {
  30. fulldomain=$1
  31. txtvalue=$2
  32. _opns_check_auth || return 1
  33. if ! rm_record "$fulldomain" "$txtvalue"; then
  34. return 1
  35. fi
  36. return 0
  37. }
  38. set_record() {
  39. fulldomain=$1
  40. new_challenge=$2
  41. _info "Adding record $fulldomain with challenge: $new_challenge"
  42. _debug "Detect root zone"
  43. if ! _get_root "$fulldomain"; then
  44. _err "invalid domain"
  45. return 1
  46. fi
  47. _debug _domain "$_domain"
  48. _debug _host "$_host"
  49. _debug _domainid "$_domainid"
  50. _return_str=""
  51. _record_string=""
  52. _build_record_string "$_domainid" "$_host" "$new_challenge"
  53. _uuid=""
  54. if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
  55. # Update
  56. if _opns_rest "POST" "/record/setRecord/${_uuid}" "$_record_string"; then
  57. _return_str="$response"
  58. else
  59. return 1
  60. fi
  61. else
  62. #create
  63. if _opns_rest "POST" "/record/addRecord" "$_record_string"; then
  64. _return_str="$response"
  65. else
  66. return 1
  67. fi
  68. fi
  69. if echo "$_return_str" | _egrep_o "\"result\":\"saved\"" >/dev/null; then
  70. _opns_rest "POST" "/service/reconfigure" "{}"
  71. _debug "Record created"
  72. else
  73. _err "Error creating record $_record_string"
  74. return 1
  75. fi
  76. return 0
  77. }
  78. rm_record() {
  79. fulldomain=$1
  80. new_challenge="$2"
  81. _info "Remove record $fulldomain with challenge: $new_challenge"
  82. _debug "Detect root zone"
  83. if ! _get_root "$fulldomain"; then
  84. _err "invalid domain"
  85. return 1
  86. fi
  87. _debug _domain "$_domain"
  88. _debug _host "$_host"
  89. _debug _domainid "$_domainid"
  90. _uuid=""
  91. if _existingchallenge "$_domain" "$_host" "$new_challenge"; then
  92. # Delete
  93. if _opns_rest "POST" "/record/delRecord/${_uuid}" "\{\}"; then
  94. if echo "$_return_str" | _egrep_o "\"result\":\"deleted\"" >/dev/null; then
  95. _opns_rest "POST" "/service/reconfigure" "{}"
  96. _debug "Record deleted"
  97. else
  98. _err "Error deleting record $_host from domain $fulldomain"
  99. return 1
  100. fi
  101. else
  102. _err "Error deleting record $_host from domain $fulldomain"
  103. return 1
  104. fi
  105. else
  106. _info "Record not found, nothing to remove"
  107. fi
  108. return 0
  109. }
  110. #################### Private functions below ##################################
  111. #_acme-challenge.www.domain.com
  112. #returns
  113. # _domainid=domid
  114. #_domain=domain.com
  115. _get_root() {
  116. domain=$1
  117. i=2
  118. p=1
  119. if _opns_rest "GET" "/domain/get"; then
  120. _domain_response="$response"
  121. else
  122. return 1
  123. fi
  124. while true; do
  125. h=$(printf "%s" "$domain" | cut -d . -f $i-100)
  126. if [ -z "$h" ]; then
  127. #not valid
  128. return 1
  129. fi
  130. _debug h "$h"
  131. id=$(echo "$_domain_response" | _egrep_o "\"[^\"]*\":{\"enabled\":\"1\",\"type\":{\"master\":{\"value\":\"master\",\"selected\":1},\"slave\":{\"value\":\"slave\",\"selected\":0}},\"masterip\":\"[^\"]*\",\"allownotifyslave\":{\"\":{[^}]*}},\"domainname\":\"${h}\"" | cut -d ':' -f 1 | cut -d '"' -f 2)
  132. if [ -n "$id" ]; then
  133. _debug id "$id"
  134. _host=$(printf "%s" "$domain" | cut -d . -f 1-$p)
  135. _domain="${h}"
  136. _domainid="${id}"
  137. return 0
  138. fi
  139. p=$i
  140. i=$(_math $i + 1)
  141. done
  142. _debug "$domain not found"
  143. return 1
  144. }
  145. _opns_rest() {
  146. method=$1
  147. ep=$2
  148. data=$3
  149. #Percent encode user and token
  150. key=$(echo "$OPNs_Key" | tr -d "\n\r" | _url_encode)
  151. token=$(echo "$OPNs_Token" | tr -d "\n\r" | _url_encode)
  152. opnsense_url="https://${key}:${token}@${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
  153. export _H1="Content-Type: application/json"
  154. _debug2 "Try to call api: https://${OPNs_Host}:${OPNs_Port:-$OPNs_DefaultPort}/api/bind${ep}"
  155. if [ ! "$method" = "GET" ]; then
  156. _debug data "$data"
  157. export _H1="Content-Type: application/json"
  158. response="$(_post "$data" "$opnsense_url" "" "$method")"
  159. else
  160. export _H1=""
  161. response="$(_get "$opnsense_url")"
  162. fi
  163. if [ "$?" != "0" ]; then
  164. _err "error $ep"
  165. return 1
  166. fi
  167. _debug2 response "$response"
  168. return 0
  169. }
  170. _build_record_string() {
  171. _record_string="{\"record\":{\"enabled\":\"1\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"}}"
  172. }
  173. _existingchallenge() {
  174. if _opns_rest "GET" "/record/searchRecord"; then
  175. _record_response="$response"
  176. else
  177. return 1
  178. fi
  179. _uuid=""
  180. _uuid=$(echo "$_record_response" | _egrep_o "\"uuid\":\"[^\"]*\",\"enabled\":\"[01]\",\"domain\":\"$1\",\"name\":\"$2\",\"type\":\"TXT\",\"value\":\"$3\"" | cut -d ':' -f 2 | cut -d '"' -f 2)
  181. if [ -n "$_uuid" ]; then
  182. _debug uuid "$_uuid"
  183. return 0
  184. fi
  185. _debug "${2}.$1{1} record not found"
  186. return 1
  187. }
  188. _opns_check_auth() {
  189. OPNs_Host="${OPNs_Host:-$(_readaccountconf_mutable OPNs_Host)}"
  190. OPNs_Port="${OPNs_Port:-$(_readaccountconf_mutable OPNs_Port)}"
  191. OPNs_Key="${OPNs_Key:-$(_readaccountconf_mutable OPNs_Key)}"
  192. OPNs_Token="${OPNs_Token:-$(_readaccountconf_mutable OPNs_Token)}"
  193. OPNs_Api_Insecure="${OPNs_Api_Insecure:-$(_readaccountconf_mutable OPNs_Api_Insecure)}"
  194. if [ -z "$OPNs_Host" ]; then
  195. _err "You don't specify OPNsense address."
  196. return 1
  197. else
  198. _saveaccountconf_mutable OPNs_Host "$OPNs_Host"
  199. fi
  200. if ! printf '%s' "$OPNs_Port" | grep '^[0-9]*$' >/dev/null; then
  201. _err 'OPNs_Port specified but not numeric value'
  202. return 1
  203. elif [ -z "$OPNs_Port" ]; then
  204. _info "OPNSense port not specified. Defaulting to using port $OPNs_DefaultPort"
  205. else
  206. _saveaccountconf_mutable OPNs_Port "$OPNs_Port"
  207. fi
  208. if ! printf '%s' "$OPNs_Api_Insecure" | grep '^[01]$' >/dev/null; then
  209. _err 'OPNs_Api_Insecure specified but not 0/1 value'
  210. return 1
  211. elif [ -n "$OPNs_Api_Insecure" ]; then
  212. _saveaccountconf_mutable OPNs_Api_Insecure "$OPNs_Api_Insecure"
  213. fi
  214. export HTTPS_INSECURE="${OPNs_Api_Insecure:-$OPNs_DefaultApi_Insecure}"
  215. if [ -z "$OPNs_Key" ]; then
  216. _err "you have not specified your OPNsense api key id."
  217. _err "Please set OPNs_Key and try again."
  218. return 1
  219. else
  220. _saveaccountconf_mutable OPNs_Key "$OPNs_Key"
  221. fi
  222. if [ -z "$OPNs_Token" ]; then
  223. _err "you have not specified your OPNsense token."
  224. _err "Please create OPNs_Token and try again."
  225. return 1
  226. else
  227. _saveaccountconf_mutable OPNs_Token "$OPNs_Token"
  228. fi
  229. if ! _opns_rest "GET" "/general/get"; then
  230. _err "Call to OPNsense API interface failed. Unable to access OPNsense API."
  231. return 1
  232. fi
  233. return 0
  234. }